mirror of https://github.com/ehang-io/nps
add functions
parent
2c608ddb7f
commit
750ecb824a
|
@ -8,11 +8,11 @@ import (
|
|||
"github.com/cnlh/nps/lib/conn"
|
||||
"github.com/cnlh/nps/lib/crypt"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
"github.com/cnlh/nps/lib/lg"
|
||||
"github.com/cnlh/nps/lib/pool"
|
||||
"github.com/cnlh/nps/lib/version"
|
||||
"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"
|
||||
"log"
|
||||
"net"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
@ -48,6 +48,7 @@ type Bridge struct {
|
|||
tunnelType string //bridge type kcp or tcp
|
||||
OpenTask chan *file.Tunnel
|
||||
CloseClient chan int
|
||||
SecretChan chan *conn.Secret
|
||||
clientLock sync.RWMutex
|
||||
Register map[string]time.Time
|
||||
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.ipVerify = ipVerify
|
||||
t.runList = runList
|
||||
t.SecretChan = make(chan *conn.Secret)
|
||||
return t
|
||||
}
|
||||
|
||||
|
@ -80,7 +82,7 @@ func (s *Bridge) StartTunnel() error {
|
|||
c, err := s.kcpListener.AcceptKCP()
|
||||
conn.SetUdpSession(c)
|
||||
if err != nil {
|
||||
lg.Println(err)
|
||||
logs.Warn(err)
|
||||
continue
|
||||
}
|
||||
go s.cliProcess(conn.NewConn(c))
|
||||
|
@ -95,7 +97,7 @@ func (s *Bridge) StartTunnel() error {
|
|||
for {
|
||||
c, err := s.tcpListener.Accept()
|
||||
if err != nil {
|
||||
lg.Println(err)
|
||||
logs.Warn(err)
|
||||
continue
|
||||
}
|
||||
go s.cliProcess(conn.NewConn(c))
|
||||
|
@ -116,6 +118,12 @@ func (s *Bridge) verifySuccess(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)
|
||||
var buf []byte
|
||||
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())
|
||||
if err != nil {
|
||||
lg.Println("当前客户端连接校验错误,关闭此客户端:", c.Conn.RemoteAddr())
|
||||
logs.Info("Current client connection validation error, close this client:", c.Conn.RemoteAddr())
|
||||
s.verifyError(c)
|
||||
return
|
||||
} else {
|
||||
|
@ -136,7 +144,7 @@ func (s *Bridge) cliProcess(c *conn.Conn) {
|
|||
if flag, err := c.ReadFlag(); err == nil {
|
||||
s.typeDeal(flag, c, id)
|
||||
} else {
|
||||
log.Println(err, flag)
|
||||
logs.Warn(err, flag)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -182,7 +190,7 @@ func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int) {
|
|||
s.Client[id] = NewClient(nil, c, nil)
|
||||
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)
|
||||
case common.WORK_CHAN:
|
||||
s.clientLock.Lock()
|
||||
|
@ -200,6 +208,10 @@ func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int) {
|
|||
go s.GetConfig(c)
|
||||
case common.WORK_REGISTER:
|
||||
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:
|
||||
s.clientLock.Lock()
|
||||
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)
|
||||
if err != nil {
|
||||
lg.Println("send link information error:", err, link.Id)
|
||||
logs.Warn("send link information error:", err, link.Id)
|
||||
s.DelClient(clientId)
|
||||
return
|
||||
}
|
||||
|
@ -314,7 +326,7 @@ func (s *Bridge) SendLinkInfo(clientId int, link *conn.Link, linkAddr string) (t
|
|||
}
|
||||
} else {
|
||||
s.clientLock.Unlock()
|
||||
err = errors.New("the connection is not connect")
|
||||
err = errors.New(fmt.Sprintf("the client %d is not connect", clientId))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -328,6 +340,7 @@ func (s *Bridge) DelClient(id int) {
|
|||
func (s *Bridge) GetConfig(c *conn.Conn) {
|
||||
var client *file.Client
|
||||
var fail bool
|
||||
|
||||
for {
|
||||
flag, err := c.ReadFlag()
|
||||
if err != nil {
|
||||
|
@ -357,19 +370,15 @@ func (s *Bridge) GetConfig(c *conn.Conn) {
|
|||
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)
|
||||
var err error
|
||||
if client, err = c.GetConfigInfo(); err != nil {
|
||||
c.Write([]byte(client.VerifyKey))
|
||||
|
||||
if config, err := c.GetConfigInfo(); err != nil {
|
||||
fail = true
|
||||
c.WriteAddFail()
|
||||
break
|
||||
} else {
|
||||
client.Cnf = config
|
||||
c.Write([]byte(client.VerifyKey))
|
||||
file.GetCsvDb().NewClient(client)
|
||||
c.WriteAddOk()
|
||||
}
|
||||
case common.NEW_HOST:
|
||||
|
@ -380,6 +389,7 @@ func (s *Bridge) GetConfig(c *conn.Conn) {
|
|||
} else if file.GetCsvDb().IsHostExist(h) {
|
||||
fail = true
|
||||
c.WriteAddFail()
|
||||
break
|
||||
} else {
|
||||
h.Client = client
|
||||
file.GetCsvDb().NewHost(h)
|
||||
|
@ -397,6 +407,13 @@ func (s *Bridge) GetConfig(c *conn.Conn) {
|
|||
fail = true
|
||||
c.WriteAddFail()
|
||||
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++ {
|
||||
tl := new(file.Tunnel)
|
||||
|
@ -407,17 +424,24 @@ func (s *Bridge) GetConfig(c *conn.Conn) {
|
|||
tl.Remark = t.Remark
|
||||
} else {
|
||||
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.Status = true
|
||||
tl.Flow = new(file.Flow)
|
||||
tl.NoStore = true
|
||||
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
|
||||
c.WriteAddFail()
|
||||
break
|
||||
} else {
|
||||
s.OpenTask <- tl
|
||||
}
|
||||
|
@ -460,7 +484,7 @@ func (s *Bridge) clientCopy(clientId int) {
|
|||
|
||||
for {
|
||||
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)
|
||||
break
|
||||
} else {
|
||||
|
@ -470,7 +494,7 @@ func (s *Bridge) clientCopy(clientId int) {
|
|||
if content, err := client.tunnel.GetMsgContent(link); err != nil {
|
||||
pool.PutBufPoolCopy(content)
|
||||
s.delClient(clientId)
|
||||
lg.Println("read msg content error", err, "close client")
|
||||
logs.Notice("read msg content error", err, "close client")
|
||||
break
|
||||
} else {
|
||||
link.MsgCh <- content
|
||||
|
|
|
@ -3,9 +3,10 @@ package client
|
|||
import (
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/conn"
|
||||
"github.com/cnlh/nps/lib/lg"
|
||||
"github.com/cnlh/nps/lib/pool"
|
||||
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
@ -40,11 +41,11 @@ func (s *TRPClient) Start() {
|
|||
retry:
|
||||
c, err := NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_MAIN, s.proxyUrl)
|
||||
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)
|
||||
goto retry
|
||||
}
|
||||
lg.Printf("Successful connection with server %s", s.svrAddr)
|
||||
logs.Info("Successful connection with server %s", s.svrAddr)
|
||||
s.processor(c)
|
||||
}
|
||||
|
||||
|
@ -65,12 +66,13 @@ func (s *TRPClient) processor(c *conn.Conn) {
|
|||
for {
|
||||
flags, err := c.ReadFlag()
|
||||
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
|
||||
}
|
||||
switch flags {
|
||||
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:
|
||||
if link, err := c.GetLinkInfo(); err != nil {
|
||||
break
|
||||
|
@ -83,12 +85,13 @@ func (s *TRPClient) processor(c *conn.Conn) {
|
|||
link.Run(false)
|
||||
}
|
||||
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:
|
||||
lg.Println("Server-side return error")
|
||||
logs.Error("Server-side return error")
|
||||
break
|
||||
default:
|
||||
lg.Println("The error could not be resolved")
|
||||
logs.Warn("The error could not be resolved")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +106,7 @@ func (s *TRPClient) linkProcess(link *conn.Link, c *conn.Conn) {
|
|||
|
||||
if err != nil {
|
||||
c.WriteFail(link.Id)
|
||||
lg.Println("connect to ", link.Host, "error:", err)
|
||||
logs.Warn("connect to ", link.Host, "error:", err)
|
||||
return
|
||||
}
|
||||
c.WriteSuccess(link.Id)
|
||||
|
@ -134,7 +137,7 @@ func (s *TRPClient) getMsgStatus() {
|
|||
var err error
|
||||
s.msgTunnel, err = NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_SEND_STATUS, s.proxyUrl)
|
||||
if err != nil {
|
||||
lg.Println("connect to ", s.svrAddr, "error:", err)
|
||||
logs.Error("connect to ", s.svrAddr, "error:", err)
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
|
@ -160,7 +163,7 @@ func (s *TRPClient) dealChan() {
|
|||
var err error
|
||||
s.tunnel, err = NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_CHAN, s.proxyUrl)
|
||||
if err != nil {
|
||||
lg.Println("connect to ", s.svrAddr, "error:", err)
|
||||
logs.Error("connect to ", s.svrAddr, "error:", err)
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/config"
|
||||
"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/golang.org/x/net/proxy"
|
||||
"io/ioutil"
|
||||
|
@ -39,7 +42,7 @@ func GetTaskStatus(path string) {
|
|||
if l, err := c.GetLen(); err != nil {
|
||||
log.Fatalln(err)
|
||||
} else if b, err := c.ReadLen(l); err != nil {
|
||||
lg.Fatalln(err)
|
||||
log.Fatalln(err)
|
||||
} else {
|
||||
arr := strings.Split(string(b), common.CONN_DATA_SEQ)
|
||||
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) {
|
||||
first := true
|
||||
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:
|
||||
if first || cnf.CommonConfig.AutoReconnection {
|
||||
if !first {
|
||||
lg.Println("Reconnecting...")
|
||||
logs.Info("Reconnecting...")
|
||||
time.Sleep(time.Second * 5)
|
||||
}
|
||||
} else {
|
||||
|
@ -90,48 +95,51 @@ re:
|
|||
first = false
|
||||
c, err := NewConn(cnf.CommonConfig.Tp, cnf.CommonConfig.VKey, cnf.CommonConfig.Server, common.WORK_CONFIG, cnf.CommonConfig.ProxyUrl)
|
||||
if err != nil {
|
||||
lg.Println(err)
|
||||
logs.Error(err)
|
||||
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
|
||||
}
|
||||
var b []byte
|
||||
if b, err = c.ReadLen(16); err != nil {
|
||||
lg.Println(err)
|
||||
logs.Error(err)
|
||||
goto re
|
||||
} else {
|
||||
ioutil.WriteFile(filepath.Join(common.GetTmpPath(), "npc_vkey.txt"), []byte(string(b)), 0600)
|
||||
}
|
||||
if !c.GetAddStatus() {
|
||||
lg.Println(errAdd)
|
||||
logs.Error(errAdd)
|
||||
goto re
|
||||
}
|
||||
|
||||
for _, v := range cnf.Hosts {
|
||||
if _, err := c.SendHostInfo(v); err != nil {
|
||||
lg.Println(err)
|
||||
logs.Error(err)
|
||||
goto re
|
||||
}
|
||||
if !c.GetAddStatus() {
|
||||
lg.Println(errAdd, v.Host)
|
||||
logs.Error(errAdd, v.Host)
|
||||
goto re
|
||||
}
|
||||
}
|
||||
for _, v := range cnf.Tasks {
|
||||
if _, err := c.SendTaskInfo(v); err != nil {
|
||||
lg.Println(err)
|
||||
logs.Error(err)
|
||||
goto re
|
||||
}
|
||||
if !c.GetAddStatus() {
|
||||
lg.Println(errAdd, v.Ports)
|
||||
logs.Error(errAdd, v.Ports)
|
||||
goto re
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range cnf.LocalServer {
|
||||
go StartLocalServer(v, cnf.CommonConfig)
|
||||
}
|
||||
c.Close()
|
||||
|
||||
NewRPClient(cnf.CommonConfig.Server, string(b), cnf.CommonConfig.Tp, cnf.CommonConfig.ProxyUrl).Start()
|
||||
CloseLocalServer()
|
||||
goto re
|
||||
}
|
||||
|
||||
|
@ -163,16 +171,30 @@ func NewConn(tp string, vkey string, server string, connType string, proxyUrl st
|
|||
return nil, err
|
||||
}
|
||||
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 {
|
||||
lg.Println(err)
|
||||
logs.Error(err)
|
||||
os.Exit(0)
|
||||
}
|
||||
if s, err := c.ReadFlag(); err != nil {
|
||||
lg.Println(err)
|
||||
logs.Error(err)
|
||||
os.Exit(0)
|
||||
} 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 {
|
||||
lg.Println(err)
|
||||
logs.Error(err)
|
||||
os.Exit(0)
|
||||
}
|
||||
c.SetAlive(tp)
|
||||
|
||||
|
|
|
@ -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,14 +5,12 @@ import (
|
|||
"github.com/cnlh/nps/client"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/daemon"
|
||||
"github.com/cnlh/nps/lib/lg"
|
||||
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const VERSION = "v0.0.15"
|
||||
|
||||
var (
|
||||
serverAddr = flag.String("server", "", "Server addr (ip:port)")
|
||||
configPath = flag.String("config", "npc.conf", "Configuration file path")
|
||||
|
@ -20,6 +18,7 @@ var (
|
|||
logType = flag.String("log", "stdout", "Log output mode(stdout|file)")
|
||||
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)")
|
||||
logLevel = flag.String("log_level", "7", "log level 0~7")
|
||||
registerTime = flag.Int("time", 2, "register time long /h")
|
||||
)
|
||||
|
||||
|
@ -37,14 +36,14 @@ func main() {
|
|||
}
|
||||
daemon.InitDaemon("npc", common.GetRunPath(), common.GetTmpPath())
|
||||
if *logType == "stdout" {
|
||||
lg.InitLogFile("npc", true, common.GetLogPath())
|
||||
logs.SetLogger(logs.AdapterConsole, `{"level":`+*logLevel+`,"color":true}`)
|
||||
} else {
|
||||
lg.InitLogFile("npc", false, common.GetLogPath())
|
||||
logs.SetLogger(logs.AdapterFile, `{"level":`+*logLevel+`,"filename":"npc_log.log"}`)
|
||||
}
|
||||
if *verifyKey != "" && *serverAddr != "" {
|
||||
for {
|
||||
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)
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -6,19 +6,18 @@ import (
|
|||
"github.com/cnlh/nps/lib/daemon"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
"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/vender/github.com/astaxie/beego"
|
||||
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
|
||||
_ "github.com/cnlh/nps/web/routers"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
const VERSION = "v0.0.15"
|
||||
|
||||
var (
|
||||
level string
|
||||
logType = flag.String("log", "stdout", "Log output mode(stdout|file)")
|
||||
)
|
||||
|
||||
|
@ -37,17 +36,22 @@ func main() {
|
|||
return
|
||||
}
|
||||
}
|
||||
if level = beego.AppConfig.String("logLevel"); level == "" {
|
||||
level = "7"
|
||||
}
|
||||
logs.Reset()
|
||||
if *logType == "stdout" {
|
||||
lg.InitLogFile("nps", true, common.GetLogPath())
|
||||
logs.SetLogger(logs.AdapterConsole, `{"level":`+level+`,"color":true}`)
|
||||
} else {
|
||||
lg.InitLogFile("nps", false, common.GetLogPath())
|
||||
logs.SetLogger(logs.AdapterFile, `{"level":`+level+`,"filename":"nps_log.log"}`)
|
||||
}
|
||||
task := &file.Tunnel{
|
||||
Mode: "webServer",
|
||||
}
|
||||
bridgePort, err := beego.AppConfig.Int("bridgePort")
|
||||
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"))
|
||||
server.StartNewServer(bridgePort, task, beego.AppConfig.String("bridgeType"))
|
||||
|
|
|
@ -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.
|
||||
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 @@
|
|||
7,7hv3avgeg2ldzvx7,,true,,,0,,0,0
|
||||
7,7hv3avgeg2ldzvx7,,true,,,1,,0,999,10
|
||||
|
|
|
|
@ -0,0 +1 @@
|
|||
b.o.com,127.0.0.1:8082,7,,,,/,3,12995709,38827
|
|
|
@ -4,32 +4,24 @@ tp=tcp
|
|||
vkey=123
|
||||
auto_reconnection=true
|
||||
crypt=true
|
||||
|
||||
[web1]
|
||||
host=a.o.com
|
||||
host_change=www.proxy.com
|
||||
target=127.0.0.1:8082
|
||||
target=127.0.0.1:8080
|
||||
location=/
|
||||
|
||||
[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
|
||||
header_set_proxy=nps
|
||||
target=127.0.0.1:8080
|
||||
location=/cdn
|
||||
|
||||
[tcp]
|
||||
mode=tcpServer
|
||||
target=8001-8005,8082
|
||||
port=9001-9005,9006
|
||||
[ssh_1118]
|
||||
mode=secretServer
|
||||
password=1111
|
||||
target=123.206.77.88:22
|
||||
|
||||
[socks5]
|
||||
mode=socks5Server
|
||||
port=9007
|
||||
|
||||
[http]
|
||||
mode=httpProxyServer
|
||||
port=9008
|
||||
|
||||
[udp]
|
||||
mode=udpServer
|
||||
port=53
|
||||
target=114.114.114.114:53
|
||||
[secret_ssh]
|
||||
password=1111
|
||||
port=1000
|
||||
|
|
|
@ -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
|
||||
|
|
|
|
@ -13,6 +13,7 @@ const (
|
|||
WORK_SEND_STATUS = "sdst"
|
||||
WORK_CONFIG = "conf"
|
||||
WORK_REGISTER = "rgst"
|
||||
WORD_SECRET = "sert"
|
||||
WORK_STATUS = "stus"
|
||||
RES_SIGN = "sign"
|
||||
RES_MSG = "msg0"
|
||||
|
@ -21,7 +22,6 @@ const (
|
|||
NEW_TASK = "task" //新连接标志
|
||||
NEW_CONF = "conf" //新连接标志
|
||||
NEW_HOST = "host" //新连接标志
|
||||
|
||||
CONN_TCP = "tcp"
|
||||
CONN_UDP = "udp"
|
||||
UnauthorizedBytes = `HTTP/1.1 401 Unauthorized
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"github.com/cnlh/nps/lib/crypt"
|
||||
"github.com/cnlh/nps/lib/pool"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
|
@ -246,3 +248,10 @@ func GetIpByAddr(addr string) string {
|
|||
arr := strings.Split(addr, ":")
|
||||
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
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
"regexp"
|
||||
|
@ -14,6 +15,11 @@ type CommonConfig struct {
|
|||
AutoReconnection bool
|
||||
Cnf *file.Config
|
||||
ProxyUrl string
|
||||
Client *file.Client
|
||||
}
|
||||
type LocalServer struct {
|
||||
Port int
|
||||
Password string
|
||||
}
|
||||
type Config struct {
|
||||
content string
|
||||
|
@ -21,6 +27,7 @@ type Config struct {
|
|||
CommonConfig *CommonConfig
|
||||
Hosts []*file.Host
|
||||
Tasks []*file.Tunnel
|
||||
LocalServer []*LocalServer
|
||||
}
|
||||
|
||||
func NewConfig(path string) (c *Config, err error) {
|
||||
|
@ -44,6 +51,11 @@ func NewConfig(path string) (c *Config, err error) {
|
|||
nextIndex = len(c.content)
|
||||
}
|
||||
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] {
|
||||
case "[common]":
|
||||
c.CommonConfig = dealCommon(nowContent)
|
||||
|
@ -68,9 +80,11 @@ func getTitleContent(s string) string {
|
|||
re, _ := regexp.Compile(`[\[\]]`)
|
||||
return re.ReplaceAllString(s, "")
|
||||
}
|
||||
|
||||
func dealCommon(s string) *CommonConfig {
|
||||
c := &CommonConfig{}
|
||||
c.Cnf = new(file.Config)
|
||||
c.Client = file.NewClient("", true, true)
|
||||
for _, v := range strings.Split(s, "\n") {
|
||||
item := strings.Split(v, "=")
|
||||
if len(item) == 0 {
|
||||
|
@ -97,10 +111,19 @@ func dealCommon(s string) *CommonConfig {
|
|||
c.Cnf.Crypt = common.GetBoolByStr(item[1])
|
||||
case "proxy_socks5_url":
|
||||
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
|
||||
}
|
||||
|
||||
func dealHost(s string) *file.Host {
|
||||
h := &file.Host{}
|
||||
var headerChange string
|
||||
|
@ -146,12 +169,35 @@ func dealTunnel(s string) *file.Tunnel {
|
|||
t.Mode = item[1]
|
||||
case "target":
|
||||
t.Target = item[1]
|
||||
case "targetAddr":
|
||||
t.TargetAddr = item[1]
|
||||
case "password":
|
||||
t.Password = item[1]
|
||||
}
|
||||
}
|
||||
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) {
|
||||
var re *regexp.Regexp
|
||||
re, err = regexp.Compile(`\[.+?\]`)
|
||||
|
@ -159,5 +205,13 @@ func getAllTitle(content string) (arr []string, err error) {
|
|||
return
|
||||
}
|
||||
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
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ import (
|
|||
"encoding/binary"
|
||||
"errors"
|
||||
"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/pool"
|
||||
"github.com/cnlh/nps/lib/rate"
|
||||
|
@ -317,7 +319,7 @@ func (s *Conn) GetHostInfo() (h *file.Host, err error) {
|
|||
}
|
||||
|
||||
//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:
|
||||
+----+-----+---------+
|
||||
|
@ -328,14 +330,15 @@ func (s *Conn) SendConfigInfo(c *file.Config) (int, error) {
|
|||
*/
|
||||
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)
|
||||
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()
|
||||
defer s.Unlock()
|
||||
return s.Write(raw.Bytes())
|
||||
}
|
||||
|
||||
//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 b []byte
|
||||
if l, err = s.GetLen(); err != nil {
|
||||
|
@ -344,12 +347,16 @@ func (s *Conn) GetConfigInfo() (c *file.Config, err error) {
|
|||
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])
|
||||
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
|
||||
}
|
||||
|
@ -366,7 +373,7 @@ func (s *Conn) SendTaskInfo(t *file.Tunnel) (int, error) {
|
|||
*/
|
||||
raw := bytes.NewBuffer([]byte{})
|
||||
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()
|
||||
defer s.Unlock()
|
||||
return s.Write(raw.Bytes())
|
||||
|
@ -390,6 +397,8 @@ func (s *Conn) GetTaskInfo() (t *file.Tunnel, err error) {
|
|||
t.Status = true
|
||||
t.Flow = new(file.Flow)
|
||||
t.Remark = arr[3]
|
||||
t.TargetAddr = arr[4]
|
||||
t.Password = arr[5]
|
||||
t.NoStore = true
|
||||
}
|
||||
return
|
||||
|
|
|
@ -8,6 +8,18 @@ import (
|
|||
"net"
|
||||
)
|
||||
|
||||
type Secret struct {
|
||||
Password string
|
||||
Conn *Conn
|
||||
}
|
||||
|
||||
func NewSecret(p string, conn *Conn) *Secret {
|
||||
return &Secret{
|
||||
Password: p,
|
||||
Conn: conn,
|
||||
}
|
||||
}
|
||||
|
||||
type Link struct {
|
||||
Id int //id
|
||||
ConnType string //连接类型
|
||||
|
|
|
@ -14,7 +14,9 @@ var (
|
|||
func GetCsvDb() *Csv {
|
||||
once.Do(func() {
|
||||
CsvDb = NewCsv(common.GetRunPath())
|
||||
CsvDb.Init()
|
||||
CsvDb.LoadClientFromCsv()
|
||||
CsvDb.LoadTaskFromCsv()
|
||||
CsvDb.LoadHostFromCsv()
|
||||
})
|
||||
return CsvDb
|
||||
}
|
||||
|
|
|
@ -3,9 +3,11 @@ package file
|
|||
import (
|
||||
"encoding/csv"
|
||||
"errors"
|
||||
"fmt"
|
||||
"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/vender/github.com/astaxie/beego/logs"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -33,17 +35,11 @@ type Csv struct {
|
|||
sync.Mutex
|
||||
}
|
||||
|
||||
func (s *Csv) Init() {
|
||||
s.LoadClientFromCsv()
|
||||
s.LoadTaskFromCsv()
|
||||
s.LoadHostFromCsv()
|
||||
}
|
||||
|
||||
func (s *Csv) StoreTasksToCsv() {
|
||||
// 创建文件
|
||||
csvFile, err := os.Create(filepath.Join(s.RunPath, "conf", "tasks.csv"))
|
||||
if err != nil {
|
||||
lg.Fatalf(err.Error())
|
||||
logs.Error(err.Error())
|
||||
}
|
||||
defer csvFile.Close()
|
||||
writer := csv.NewWriter(csvFile)
|
||||
|
@ -59,10 +55,13 @@ func (s *Csv) StoreTasksToCsv() {
|
|||
strconv.Itoa(task.Id),
|
||||
strconv.Itoa(task.Client.Id),
|
||||
task.Remark,
|
||||
strconv.Itoa(int(task.Flow.ExportFlow)),
|
||||
strconv.Itoa(int(task.Flow.InletFlow)),
|
||||
task.Password,
|
||||
}
|
||||
err := writer.Write(record)
|
||||
if err != nil {
|
||||
lg.Fatalf(err.Error())
|
||||
logs.Error(err.Error())
|
||||
}
|
||||
}
|
||||
writer.Flush()
|
||||
|
@ -90,7 +89,8 @@ func (s *Csv) LoadTaskFromCsv() {
|
|||
path := filepath.Join(s.RunPath, "conf", "tasks.csv")
|
||||
records, err := s.openFile(path)
|
||||
if err != nil {
|
||||
lg.Fatalln("配置文件打开错误:", path)
|
||||
logs.Error("Profile Opening Error:", path)
|
||||
os.Exit(0)
|
||||
}
|
||||
var tasks []*Tunnel
|
||||
// 将每一行数据保存到内存slice中
|
||||
|
@ -102,8 +102,11 @@ func (s *Csv) LoadTaskFromCsv() {
|
|||
Status: common.GetBoolByStr(item[3]),
|
||||
Id: common.GetIntNoErrByStr(item[4]),
|
||||
Remark: item[6],
|
||||
Password: item[9],
|
||||
}
|
||||
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 {
|
||||
continue
|
||||
}
|
||||
|
@ -142,10 +145,16 @@ func (s *Csv) GetIdByVerifyKey(vKey string, addr string) (int, error) {
|
|||
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)
|
||||
s.Tasks = append(s.Tasks, t)
|
||||
s.StoreTasksToCsv()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Csv) UpdateTask(t *Tunnel) error {
|
||||
|
@ -171,6 +180,16 @@ func (s *Csv) DelTask(id int) error {
|
|||
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) {
|
||||
for _, v = range s.Tasks {
|
||||
if v.Id == id {
|
||||
|
@ -205,6 +224,8 @@ func (s *Csv) StoreHostToCsv() {
|
|||
host.Remark,
|
||||
host.Location,
|
||||
strconv.Itoa(host.Id),
|
||||
strconv.Itoa(int(host.Flow.ExportFlow)),
|
||||
strconv.Itoa(int(host.Flow.InletFlow)),
|
||||
}
|
||||
err1 := writer.Write(record)
|
||||
if err1 != nil {
|
||||
|
@ -219,7 +240,8 @@ func (s *Csv) LoadClientFromCsv() {
|
|||
path := filepath.Join(s.RunPath, "conf", "clients.csv")
|
||||
records, err := s.openFile(path)
|
||||
if err != nil {
|
||||
lg.Fatalln("配置文件打开错误:", path)
|
||||
logs.Error("Profile Opening Error:", path)
|
||||
os.Exit(0)
|
||||
}
|
||||
var clients []*Client
|
||||
// 将每一行数据保存到内存slice中
|
||||
|
@ -236,6 +258,7 @@ func (s *Csv) LoadClientFromCsv() {
|
|||
Crypt: common.GetBoolByStr(item[6]),
|
||||
Compress: item[7],
|
||||
},
|
||||
MaxConn: common.GetIntNoErrByStr(item[10]),
|
||||
}
|
||||
if post.Id > s.ClientIncreaseId {
|
||||
s.ClientIncreaseId = post.Id
|
||||
|
@ -255,7 +278,8 @@ func (s *Csv) LoadHostFromCsv() {
|
|||
path := filepath.Join(s.RunPath, "conf", "hosts.csv")
|
||||
records, err := s.openFile(path)
|
||||
if err != nil {
|
||||
lg.Fatalln("配置文件打开错误:", path)
|
||||
logs.Error("Profile Opening Error:", path)
|
||||
os.Exit(0)
|
||||
}
|
||||
var hosts []*Host
|
||||
// 将每一行数据保存到内存slice中
|
||||
|
@ -273,6 +297,8 @@ func (s *Csv) LoadHostFromCsv() {
|
|||
continue
|
||||
}
|
||||
post.Flow = new(Flow)
|
||||
post.Flow.ExportFlow = int64(common.GetIntNoErrByStr(item[8]))
|
||||
post.Flow.InletFlow = int64(common.GetIntNoErrByStr(item[9]))
|
||||
hosts = append(hosts, post)
|
||||
if post.Id > s.HostIncreaseId {
|
||||
s.HostIncreaseId = post.Id
|
||||
|
@ -350,7 +376,9 @@ func (s *Csv) NewClient(c *Client) {
|
|||
if c.Id == 0 {
|
||||
c.Id = s.GetClientId()
|
||||
}
|
||||
if c.Flow == nil {
|
||||
c.Flow = new(Flow)
|
||||
}
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
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
|
||||
func (s *Csv) GetInfoByHost(host string, r *http.Request) (h *Host, err error) {
|
||||
var hosts []*Host
|
||||
//Handling Ported Access
|
||||
host = common.GetIpByAddr(host)
|
||||
for _, v := range s.Hosts {
|
||||
//Remove http(s) http(s)://a.proxy.com
|
||||
//*.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"))
|
||||
if err != nil {
|
||||
lg.Fatalln(err.Error())
|
||||
logs.Error(err.Error())
|
||||
}
|
||||
defer csvFile.Close()
|
||||
writer := csv.NewWriter(csvFile)
|
||||
|
@ -486,10 +516,11 @@ func (s *Csv) StoreClientsToCsv() {
|
|||
client.Cnf.Compress,
|
||||
strconv.Itoa(client.RateLimit),
|
||||
strconv.Itoa(int(client.Flow.FlowLimit)),
|
||||
strconv.Itoa(int(client.MaxConn)),
|
||||
}
|
||||
err := writer.Write(record)
|
||||
if err != nil {
|
||||
lg.Fatalln(err.Error())
|
||||
logs.Error(err.Error())
|
||||
}
|
||||
}
|
||||
writer.Flush()
|
||||
|
|
|
@ -33,6 +33,8 @@ type Client struct {
|
|||
Rate *rate.Rate //速度控制
|
||||
NoStore bool
|
||||
NoDisplay bool
|
||||
MaxConn int //客户端最大连接数
|
||||
NowConn int //当前连接数
|
||||
id int
|
||||
sync.RWMutex
|
||||
}
|
||||
|
@ -62,6 +64,26 @@ func (s *Client) GetId() int {
|
|||
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 {
|
||||
Id int //Id
|
||||
Port int //服务端监听端口
|
||||
|
@ -72,7 +94,9 @@ type Tunnel struct {
|
|||
Client *Client //所属客户端id
|
||||
Ports string //客户端与服务端传递
|
||||
Flow *Flow
|
||||
Password string //私密模式密码,唯一
|
||||
Remark string //备注
|
||||
TargetAddr string
|
||||
NoStore bool
|
||||
}
|
||||
|
||||
|
@ -114,15 +138,3 @@ func (s *Host) GetRandomTarget() string {
|
|||
}
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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...)
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package version
|
||||
|
||||
const VERSION = "0.0.16"
|
||||
const VERSION_OK = "vrok"
|
||||
|
||||
func GetVersion() string {
|
||||
return VERSION
|
||||
}
|
|
@ -17,8 +17,8 @@ type Service interface {
|
|||
Close() error
|
||||
}
|
||||
|
||||
//server base struct
|
||||
type server struct {
|
||||
//Server BaseServer struct
|
||||
type BaseServer struct {
|
||||
id int
|
||||
bridge *bridge.Bridge
|
||||
task *file.Tunnel
|
||||
|
@ -26,21 +26,30 @@ type server struct {
|
|||
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()
|
||||
defer s.Unlock()
|
||||
s.task.Flow.ExportFlow += out
|
||||
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()
|
||||
defer s.Unlock()
|
||||
host.Flow.ExportFlow += out
|
||||
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 _, err := tunnel.SendMsg(rb, link); err != nil {
|
||||
c.Close()
|
||||
|
@ -68,16 +77,17 @@ func (s *server) linkCopy(link *conn.Link, c *conn.Conn, rb []byte, tunnel *conn
|
|||
}
|
||||
<-link.StatusCh
|
||||
}
|
||||
s.task.Client.AddConn()
|
||||
pool.PutBufPoolCopy(buf)
|
||||
}
|
||||
|
||||
func (s *server) writeConnFail(c net.Conn) {
|
||||
func (s *BaseServer) writeConnFail(c net.Conn) {
|
||||
c.Write([]byte(common.ConnectionFailBytes))
|
||||
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) {
|
||||
c.Write([]byte(common.UnauthorizedBytes))
|
||||
c.Close()
|
||||
|
@ -86,9 +96,23 @@ func (s *server) auth(r *http.Request, c *conn.Conn, u, p string) error {
|
|||
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) {
|
||||
return errors.New("Traffic exceeded")
|
||||
}
|
||||
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
|
||||
}
|
||||
|
|
|
@ -7,17 +7,18 @@ import (
|
|||
"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/vender/github.com/astaxie/beego"
|
||||
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type httpServer struct {
|
||||
server
|
||||
BaseServer
|
||||
httpPort int //http端口
|
||||
httpsPort int //https监听端口
|
||||
pemPath string
|
||||
|
@ -31,7 +32,7 @@ func NewHttp(bridge *bridge.Bridge, c *file.Tunnel) *httpServer {
|
|||
pemPath := beego.AppConfig.String("pemPath")
|
||||
keyPath := beego.AppConfig.String("keyPath")
|
||||
return &httpServer{
|
||||
server: server{
|
||||
BaseServer: BaseServer{
|
||||
task: c,
|
||||
bridge: bridge,
|
||||
Mutex: sync.Mutex{},
|
||||
|
@ -54,26 +55,30 @@ func (s *httpServer) Start() error {
|
|||
if s.httpPort > 0 {
|
||||
http = s.NewServer(s.httpPort)
|
||||
go func() {
|
||||
lg.Println("Start http listener, port is", s.httpPort)
|
||||
logs.Info("Start http listener, port is", s.httpPort)
|
||||
err := http.ListenAndServe()
|
||||
if err != nil {
|
||||
lg.Fatalln(err)
|
||||
logs.Error(err)
|
||||
os.Exit(0)
|
||||
}
|
||||
}()
|
||||
}
|
||||
if s.httpsPort > 0 {
|
||||
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) {
|
||||
lg.Fatalf("ssl keyFile %s exist", s.keyPath)
|
||||
logs.Error("ssl keyFile %s exist", s.keyPath)
|
||||
os.Exit(0)
|
||||
}
|
||||
https = s.NewServer(s.httpsPort)
|
||||
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)
|
||||
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
|
||||
)
|
||||
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
|
||||
} else if !host.Client.GetConn() {
|
||||
logs.Notice("Connections exceed the current client %d limit", host.Client.Id)
|
||||
c.Close()
|
||||
return
|
||||
} 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
|
||||
}
|
||||
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)
|
||||
if tunnel, err = s.bridge.SendLinkInfo(host.Client.Id, lk, c.Conn.RemoteAddr().String()); err != nil {
|
||||
lg.Println(err)
|
||||
logs.Notice(err)
|
||||
break
|
||||
}
|
||||
lk.Run(true)
|
||||
isConn = false
|
||||
} else {
|
||||
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 {
|
||||
break
|
||||
}
|
||||
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
|
||||
} else if host != lastHost {
|
||||
lastHost = host
|
||||
isConn = true
|
||||
host.Client.AddConn()
|
||||
goto start
|
||||
}
|
||||
}
|
||||
|
@ -176,6 +188,9 @@ end:
|
|||
tunnel.SendMsg([]byte(common.IO_EOF), lk)
|
||||
}
|
||||
c.Close()
|
||||
if host != nil {
|
||||
host.Client.AddConn()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *httpServer) NewServer(port int) *http.Server {
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"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/vender/github.com/astaxie/beego/logs"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
|
@ -48,7 +48,7 @@ const (
|
|||
)
|
||||
|
||||
type Sock5ModeServer struct {
|
||||
server
|
||||
BaseServer
|
||||
listener net.Listener
|
||||
}
|
||||
|
||||
|
@ -67,7 +67,7 @@ func (s *Sock5ModeServer) handleRequest(c net.Conn) {
|
|||
_, err := io.ReadFull(c, header)
|
||||
|
||||
if err != nil {
|
||||
lg.Println("illegal request", err)
|
||||
logs.Warn("illegal request", err)
|
||||
c.Close()
|
||||
return
|
||||
}
|
||||
|
@ -165,7 +165,6 @@ func (s *Sock5ModeServer) handleBind(c net.Conn) {
|
|||
|
||||
//udp
|
||||
func (s *Sock5ModeServer) handleUDP(c net.Conn) {
|
||||
lg.Println("UDP Associate")
|
||||
/*
|
||||
+----+------+------+----------+----------+----------+
|
||||
|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
|
||||
if buf[2] != 0 {
|
||||
// does not support fragmentation, drop it
|
||||
lg.Println("does not support fragmentation, drop")
|
||||
logs.Warn("does not support fragmentation, drop")
|
||||
dummy := make([]byte, maxUDPPacketSize)
|
||||
c.Read(dummy)
|
||||
}
|
||||
|
@ -190,13 +189,13 @@ func (s *Sock5ModeServer) handleUDP(c net.Conn) {
|
|||
func (s *Sock5ModeServer) handleConn(c net.Conn) {
|
||||
buf := make([]byte, 2)
|
||||
if _, err := io.ReadFull(c, buf); err != nil {
|
||||
lg.Println("negotiation err", err)
|
||||
logs.Warn("negotiation err", err)
|
||||
c.Close()
|
||||
return
|
||||
}
|
||||
|
||||
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()
|
||||
return
|
||||
}
|
||||
|
@ -204,7 +203,7 @@ func (s *Sock5ModeServer) handleConn(c net.Conn) {
|
|||
|
||||
methods := make([]byte, nMethods)
|
||||
if len, err := c.Read(methods); len != int(nMethods) || err != nil {
|
||||
lg.Println("wrong method")
|
||||
logs.Warn("wrong method")
|
||||
c.Close()
|
||||
return
|
||||
}
|
||||
|
@ -213,7 +212,7 @@ func (s *Sock5ModeServer) handleConn(c net.Conn) {
|
|||
c.Write(buf)
|
||||
if err := s.Auth(c); err != nil {
|
||||
c.Close()
|
||||
lg.Println("Validation failed:", err)
|
||||
logs.Warn("Validation failed:", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
|
@ -271,9 +270,15 @@ func (s *Sock5ModeServer) Start() error {
|
|||
if strings.Contains(err.Error(), "use of closed network connection") {
|
||||
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()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -6,15 +6,16 @@ import (
|
|||
"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/vender/github.com/astaxie/beego"
|
||||
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type TunnelModeServer struct {
|
||||
server
|
||||
BaseServer
|
||||
process process
|
||||
listener *net.TCPListener
|
||||
}
|
||||
|
@ -41,24 +42,16 @@ func (s *TunnelModeServer) Start() error {
|
|||
if strings.Contains(err.Error(), "use of closed network connection") {
|
||||
break
|
||||
}
|
||||
lg.Println(err)
|
||||
logs.Info(err)
|
||||
continue
|
||||
}
|
||||
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)
|
||||
}
|
||||
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)
|
||||
logs.Info("Connections exceed the current client %d limit", s.task.Client.Id)
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -70,17 +63,18 @@ func (s *TunnelModeServer) Close() error {
|
|||
|
||||
//web管理方式
|
||||
type WebServer struct {
|
||||
server
|
||||
BaseServer
|
||||
}
|
||||
|
||||
//开始
|
||||
func (s *WebServer) Start() error {
|
||||
p, _ := beego.AppConfig.Int("httpport")
|
||||
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
|
||||
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.SetViewsPath(filepath.Join(common.GetRunPath(), "web", "views"))
|
||||
beego.Run()
|
||||
|
@ -102,23 +96,23 @@ type process func(c *conn.Conn, s *TunnelModeServer) error
|
|||
|
||||
//tcp隧道模式
|
||||
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代理模式
|
||||
func ProcessHttp(c *conn.Conn, s *TunnelModeServer) error {
|
||||
method, addr, rb, err, r := c.GetHost()
|
||||
_, addr, rb, err, r := c.GetHost()
|
||||
if err != nil {
|
||||
c.Close()
|
||||
lg.Println(err)
|
||||
logs.Info(err)
|
||||
return err
|
||||
}
|
||||
if r.Method == "CONNECT" {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
return s.dealClient(c, s.task.Client.Cnf, addr, method, rb)
|
||||
return s.DealClient(c, addr, rb)
|
||||
}
|
||||
|
|
|
@ -6,12 +6,13 @@ import (
|
|||
"github.com/cnlh/nps/lib/conn"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
"github.com/cnlh/nps/lib/pool"
|
||||
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type UdpModeServer struct {
|
||||
server
|
||||
BaseServer
|
||||
listener *net.UDPConn
|
||||
udpMap map[string]*conn.Conn
|
||||
}
|
||||
|
@ -40,6 +41,7 @@ func (s *UdpModeServer) Start() error {
|
|||
}
|
||||
continue
|
||||
}
|
||||
logs.Trace("New ydo connection,client %d,remote address %s", s.task.Client.Id, addr)
|
||||
go s.process(addr, buf[:n])
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -5,10 +5,12 @@ import (
|
|||
"github.com/cnlh/nps/bridge"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
"github.com/cnlh/nps/lib/lg"
|
||||
"github.com/cnlh/nps/server/proxy"
|
||||
"github.com/cnlh/nps/server/tool"
|
||||
"github.com/cnlh/nps/vender/github.com/astaxie/beego"
|
||||
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -31,7 +33,6 @@ func InitFromCsv() {
|
|||
//Initialize services in server-side files
|
||||
for _, v := range file.GetCsvDb().Tasks {
|
||||
if v.Status {
|
||||
lg.Println("task start info: mode:", v.Mode, "port:", v.Port)
|
||||
AddTask(v)
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +46,19 @@ func DealBridgeTask() {
|
|||
case id := <-Bridge.CloseClient:
|
||||
DelTunnelAndHostByClientId(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) {
|
||||
Bridge = bridge.NewTunnel(bridgePort, bridgeType, common.GetBoolByStr(beego.AppConfig.String("ipLimit")), RunList)
|
||||
if err := Bridge.StartTunnel(); err != nil {
|
||||
lg.Fatalln("服务端开启失败", err)
|
||||
logs.Error("服务端开启失败", err)
|
||||
os.Exit(0)
|
||||
} 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()
|
||||
if svr := NewMode(Bridge, cnf); svr != nil {
|
||||
if err := svr.Start(); err != nil {
|
||||
lg.Fatalln(err)
|
||||
logs.Error(err)
|
||||
}
|
||||
RunList[cnf.Id] = svr
|
||||
} else {
|
||||
lg.Fatalln("启动模式%s不正确", cnf.Mode)
|
||||
logs.Error("Incorrect startup mode %s", cnf.Mode)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,13 +118,13 @@ func StopServer(id int) error {
|
|||
if err := svr.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if t, err := file.GetCsvDb().GetTask(id); err != nil {
|
||||
return err
|
||||
} else {
|
||||
t.Status = false
|
||||
file.GetCsvDb().UpdateTask(t)
|
||||
}
|
||||
}
|
||||
delete(RunList, id)
|
||||
return nil
|
||||
}
|
||||
|
@ -118,15 +133,24 @@ func StopServer(id int) error {
|
|||
|
||||
//add task
|
||||
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" {
|
||||
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")
|
||||
}
|
||||
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 {
|
||||
logs.Info("tunnel task %s start mode:%s port %d", t.Remark, t.Mode, t.Port)
|
||||
RunList[t.Id] = svr
|
||||
go func() {
|
||||
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)
|
||||
return
|
||||
}
|
||||
|
@ -272,5 +296,21 @@ func GetDashboardData() map[string]int {
|
|||
data["udpServerCount"] += 1
|
||||
}
|
||||
}
|
||||
tcpCount := 0
|
||||
for _, v := range file.GetCsvDb().Clients {
|
||||
tcpCount += v.NowConn
|
||||
}
|
||||
data["tcpCount"] = tcpCount
|
||||
return data
|
||||
}
|
||||
|
||||
func flowSession(m time.Duration) {
|
||||
ticker := time.NewTicker(m)
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
file.GetCsvDb().StoreHostToCsv()
|
||||
file.GetCsvDb().StoreTasksToCsv()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,9 @@ func init() {
|
|||
}
|
||||
|
||||
func TestServerPort(p int, m string) (b bool) {
|
||||
if p > 65535 || p <= 0 {
|
||||
return false
|
||||
}
|
||||
if len(ports) != 0 {
|
||||
if !common.InIntArr(ports, p) {
|
||||
return false
|
||||
|
|
|
@ -42,6 +42,7 @@ func (s *ClientController) Add() {
|
|||
Crypt: s.GetBoolNoErr("crypt"),
|
||||
},
|
||||
RateLimit: s.GetIntNoErr("rate_limit"),
|
||||
MaxConn: s.GetIntNoErr("max_conn"),
|
||||
Flow: &file.Flow{
|
||||
ExportFlow: 0,
|
||||
InletFlow: 0,
|
||||
|
@ -94,6 +95,7 @@ func (s *ClientController) Edit() {
|
|||
c.Cnf.Crypt = s.GetBoolNoErr("crypt")
|
||||
c.Flow.FlowLimit = int64(s.GetIntNoErr("flow_limit"))
|
||||
c.RateLimit = s.GetIntNoErr("rate_limit")
|
||||
c.MaxConn = s.GetIntNoErr("max_conn")
|
||||
if c.Rate != nil {
|
||||
c.Rate.Stop()
|
||||
}
|
||||
|
|
|
@ -44,6 +44,12 @@ func (s *IndexController) Http() {
|
|||
s.display("index/list")
|
||||
}
|
||||
|
||||
func (s *IndexController) Secret() {
|
||||
s.SetInfo("私密代理管理")
|
||||
s.SetType("secretServer")
|
||||
s.display("index/list")
|
||||
}
|
||||
|
||||
func (s *IndexController) Host() {
|
||||
s.SetInfo("host模式管理")
|
||||
s.SetType("hostServer")
|
||||
|
@ -80,6 +86,7 @@ func (s *IndexController) Add() {
|
|||
Id: file.GetCsvDb().GetTaskId(),
|
||||
Status: true,
|
||||
Remark: s.GetString("remark"),
|
||||
Password: s.GetString("password"),
|
||||
Flow: &file.Flow{},
|
||||
}
|
||||
if !tool.TestServerPort(t.Port, t.Mode) {
|
||||
|
@ -126,6 +133,7 @@ func (s *IndexController) Edit() {
|
|||
t.Port = s.GetIntNoErr("port")
|
||||
t.Mode = s.GetString("type")
|
||||
t.Target = s.GetString("target")
|
||||
t.Password = s.GetString("password")
|
||||
t.Id = id
|
||||
t.Remark = s.GetString("remark")
|
||||
if t.Client, err = file.GetCsvDb().GetClient(s.GetIntNoErr("client_id")); err != nil {
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
<label class="control-label">速度限制(单位:KB,为空不限制)</label>
|
||||
<input class="form-control" type="text" name="rate_limit" placeholder="为空不限制">
|
||||
</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">
|
||||
<label class="control-label">验证用户名(仅socks5,web穿透支持)</label>
|
||||
<input class="form-control" type="text" name="u" placeholder="不填则无需验证">
|
||||
|
|
|
@ -19,6 +19,11 @@
|
|||
<input class="form-control" value="{{.c.RateLimit}}" type="text" name="rate_limit"
|
||||
placeholder="为空不限制">
|
||||
</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">
|
||||
<label class="control-label">验证用户名(仅socks5,web穿透支持)</label>
|
||||
<input class="form-control" value="{{.c.Cnf.U}}" type="text" name="u"
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
<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 "httpProxyServer" .type}}selected{{end}} value="httpProxyServer">http代理
|
||||
<option {{if eq "secretServer" .type}}selected{{end}} value="secretServer">私密代理
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
|
@ -30,6 +31,11 @@
|
|||
<input value="{{.client_id}}" class="form-control" type="text" name="client_id"
|
||||
placeholder="客户端id">
|
||||
</div>
|
||||
<div class="form-group" id="password">
|
||||
<label class="control-label">私密模式唯一密钥</label>
|
||||
<input class="form-control" type="text" name="password"
|
||||
placeholder="私密模式唯一密钥">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<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["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["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"]
|
||||
|
||||
function resetForm() {
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
<option {{if eq "socks5Server" .t.Mode}}selected{{end}} value="socks5Server">socks5代理
|
||||
</option>
|
||||
<option {{if eq "httpProxyServer" .t.Mode}}selected{{end}} value="httpProxyServer">http代理
|
||||
<option {{if eq "secretServer" .t.Mode}}selected{{end}} value="secretServer">私密代理
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
|
@ -34,6 +35,11 @@
|
|||
<input class="form-control" value="{{.t.Client.Id}}" type="text" name="client_id"
|
||||
placeholder="客户端id">
|
||||
</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>
|
||||
</div>
|
||||
<div class="tile-footer">
|
||||
|
@ -52,6 +58,7 @@
|
|||
arr["udpServer"] = ["type", "port", "target", "compress"]
|
||||
arr["socks5Server"] = ["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"]
|
||||
|
||||
function resetForm() {
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
<div class="col-md-3">
|
||||
<div class="widget-small danger coloured-icon"><i class="icon fa fa-home fa-3x"></i>
|
||||
<div class="info">
|
||||
<h4>域名解析数</h4>
|
||||
<p><b>{{.data.hostCount}}</b></p>
|
||||
<h4>当前TCP连接总数</h4>
|
||||
<p><b>{{.data.tcpCount}}</b></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -51,9 +51,11 @@
|
|||
<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>
|
||||
<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
|
||||
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
|
||||
class="app-menu__icon fa fa-question-circle"></i><span class="app-menu__label">使用说明</span></a></li>
|
||||
</ul>
|
||||
|
|
Loading…
Reference in New Issue