diff --git a/bridge/bridge.go b/bridge/bridge.go index 283ac6a..1dc67a7 100755 --- a/bridge/bridge.go +++ b/bridge/bridge.go @@ -173,7 +173,7 @@ func (s *Bridge) cliProcess(c *conn.Conn) { } //write server version to client c.Write([]byte(crypt.Md5(version.GetVersion()))) - c.SetReadDeadlineByType(5, s.tunnelType) + c.SetReadDeadlineBySecond(5) var buf []byte var err error //get vKey from client @@ -318,9 +318,12 @@ func (s *Bridge) SendLinkInfo(clientId int, link *conn.Link, linkAddr string, t return } if t != nil && t.Mode == "file" { + //TODO if t.mode is file ,not use crypt or compress + link.Crypt = false + link.Compress = false return } - if _, err = conn.NewConn(target).SendLinkInfo(link); err != nil { + if _, err = conn.NewConn(target).SendInfo(link, ""); err != nil { logs.Info("new connect error ,the target %s refuse to connect", link.Host) return } @@ -445,7 +448,7 @@ loop: fail = true c.WriteAddFail() break loop - } else if t.Mode == "secret" { + } else if t.Mode == "secret" || t.Mode == "p2p" { ports = append(ports, 0) } if len(ports) == 0 { diff --git a/client/control.go b/client/control.go index 36a56f3..d34165a 100644 --- a/client/control.go +++ b/client/control.go @@ -87,7 +87,7 @@ func StartFromFile(path string) { first := true cnf, err := config.NewConfig(path) if err != nil || cnf.CommonConfig == nil { - logs.Error("Config file %s loading error", path) + logs.Error("Config file %s loading error %s", path, err.Error()) os.Exit(0) } logs.Info("Loading configuration file %s successfully", path) @@ -115,12 +115,12 @@ re: vkey := cnf.CommonConfig.VKey if isPub { // send global configuration to server and get status of config setting - if _, err := c.SendConfigInfo(cnf.CommonConfig); err != nil { + if _, err := c.SendInfo(cnf.CommonConfig.Client, common.NEW_CONF); err != nil { logs.Error(err) goto re } if !c.GetAddStatus() { - logs.Error(errAdd) + logs.Error("the web_user may have been occupied!") goto re } @@ -134,7 +134,7 @@ re: //send hosts to server for _, v := range cnf.Hosts { - if _, err := c.SendHostInfo(v); err != nil { + if _, err := c.SendInfo(v, common.NEW_HOST); err != nil { logs.Error(err) goto re } @@ -146,12 +146,12 @@ re: //send task to server for _, v := range cnf.Tasks { - if _, err := c.SendTaskInfo(v); err != nil { + if _, err := c.SendInfo(v, common.NEW_TASK); err != nil { logs.Error(err) goto re } if !c.GetAddStatus() { - logs.Error(errAdd, v.Ports) + logs.Error(errAdd, v.Ports, v.Remark) goto re } if v.Mode == "file" { @@ -166,7 +166,11 @@ re: } c.Close() - logs.Notice("web access login key ", vkey) + if cnf.CommonConfig.Client.WebUserName == "" || cnf.CommonConfig.Client.WebPassword == "" { + logs.Notice("web access login username:user password:%s", vkey) + } else { + logs.Notice("web access login username:%s password:%s", cnf.CommonConfig.Client.WebUserName, cnf.CommonConfig.Client.WebPassword) + } NewRPClient(cnf.CommonConfig.Server, vkey, cnf.CommonConfig.Tp, cnf.CommonConfig.ProxyUrl, cnf).Start() CloseLocalServer() goto re diff --git a/client/local.go b/client/local.go index c6bc7ae..1160b2b 100644 --- a/client/local.go +++ b/client/local.go @@ -86,12 +86,13 @@ func processP2P(localTcpConn net.Conn, config *config.CommonConfig, l *config.Lo logs.Error(err) return } - link := conn.NewLink(common.CONN_TCP, l.Target, config.Cnf.Crypt, config.Cnf.Compress, localTcpConn.LocalAddr().String()) - if _, err := conn.NewConn(nowConn).SendLinkInfo(link); err != nil { + //TODO just support compress now because there is not tls file in client packages + link := conn.NewLink(common.CONN_TCP, l.Target, false, config.Client.Cnf.Compress, localTcpConn.LocalAddr().String()) + if _, err := conn.NewConn(nowConn).SendInfo(link, ""); err != nil { logs.Error(err) return } - conn.CopyWaitGroup(nowConn, localTcpConn, config.Cnf.Crypt, config.Cnf.Compress, nil, nil, false, nil) + conn.CopyWaitGroup(nowConn, localTcpConn, false, config.Client.Cnf.Compress, nil, nil, false, nil) } func newUdpConn(config *config.CommonConfig, l *config.LocalServer) { diff --git a/conf/npc.conf b/conf/npc.conf index 0c01281..281b540 100644 --- a/conf/npc.conf +++ b/conf/npc.conf @@ -3,6 +3,15 @@ server_addr=127.0.0.1:8024 conn_type=tcp vkey=123 auto_reconnection=true +max_conn=1000 +flow_limit=1000 +rate_limit=1000 +basic_username=11 +basic_password=3 +web_username=user +web_password=1234 +crypt=true +compress=true [health_check_test1] health_check_timeout=1 @@ -18,9 +27,10 @@ health_check_max_failed=3 health_check_interval=1 health_check_type=tcp health_check_target=127.0.0.1:8083,127.0.0.1:8082 + [web] -host=b.o.com -target_addr=127.0.0.1:8080,127.0.0.1:8082 +host=c.o.com +target_addr=127.0.0.1:8083,127.0.0.1:8082 [tcp] mode=tcp @@ -29,29 +39,37 @@ server_port=10000 [socks5] mode=socks5 -server_port=9005 - -[http] -mode=httpProxy -server_port=9004 - +server_port=19009 [file] mode=file -server_port=9009 +server_port=19008 local_path=./ strip_pre=/web/ +[http] +mode=httpProxy +server_port=19004 + [udp] mode=udp -server_port=53 +server_port=12253 target_addr=114.114.114.114:53 +[ssh_secret] +mode=secret +password=ssh2 +target_addr=123.206.77.88:22 + +[ssh_p2p] +mode=p2p +password=ssh3 + [secret_ssh] local_port=2001 -password=sec +password=ssh2 [p2p_ssh] local_port=2002 -password=ppp -target_addr=192.168.74.199:22 \ No newline at end of file +password=ssh3 +target_addr=123.206.77.88:22 \ No newline at end of file diff --git a/lib/config/config.go b/lib/config/config.go index d771b2e..e0bb3c2 100644 --- a/lib/config/config.go +++ b/lib/config/config.go @@ -2,6 +2,7 @@ package config import ( "errors" + "fmt" "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/file" "regexp" @@ -13,7 +14,6 @@ type CommonConfig struct { VKey string Tp string //bridgeType kcp or tcp AutoReconnection bool - Cnf *file.Config ProxyUrl string Client *file.Client } @@ -104,8 +104,8 @@ func getTitleContent(s string) string { func dealCommon(s string) *CommonConfig { c := &CommonConfig{} - c.Cnf = new(file.Config) c.Client = file.NewClient("", true, true) + c.Client.Cnf = new(file.Config) for _, v := range splitStr(s) { item := strings.Split(v, "=") if len(item) == 0 { @@ -122,14 +122,18 @@ func dealCommon(s string) *CommonConfig { c.Tp = item[1] case "auto_reconnection": c.AutoReconnection = common.GetBoolByStr(item[1]) - case "username": - c.Cnf.U = item[1] - case "password": - c.Cnf.P = item[1] + case "basic_username": + c.Client.Cnf.U = item[1] + case "basic_password": + c.Client.Cnf.P = item[1] + case "web_password": + c.Client.WebPassword = item[1] + case "web_username": + c.Client.WebUserName = item[1] case "compress": - c.Cnf.Compress = common.GetBoolByStr(item[1]) + c.Client.Cnf.Compress = common.GetBoolByStr(item[1]) case "crypt": - c.Cnf.Crypt = common.GetBoolByStr(item[1]) + c.Client.Cnf.Crypt = common.GetBoolByStr(item[1]) case "proxy_url": c.ProxyUrl = item[1] case "rate_limit": @@ -270,7 +274,7 @@ func getAllTitle(content string) (arr []string, err error) { 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") + err = errors.New(fmt.Sprintf("Item names %s are not allowed to be duplicated", v)) return } m[v] = true diff --git a/lib/conn/conn.go b/lib/conn/conn.go index 7763dbc..53bbc65 100755 --- a/lib/conn/conn.go +++ b/lib/conn/conn.go @@ -4,9 +4,9 @@ import ( "bufio" "bytes" "encoding/binary" + "encoding/json" "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/mux" @@ -84,26 +84,6 @@ func (s *Conn) GetShortContent(l int) (b []byte, err error) { return buf, binary.Read(s, binary.LittleEndian, &buf) } -func (s *Conn) LocalAddr() net.Addr { - return s.Conn.LocalAddr() -} - -func (s *Conn) RemoteAddr() net.Addr { - return s.Conn.RemoteAddr() -} - -func (s *Conn) SetDeadline(t time.Time) error { - return s.Conn.SetDeadline(t) -} - -func (s *Conn) SetWriteDeadline(t time.Time) error { - return s.Conn.SetWriteDeadline(t) -} - -func (s *Conn) SetReadDeadline(t time.Time) error { - return s.Conn.SetReadDeadline(t) -} - //读取指定长度内容 func (s *Conn) ReadLen(cLen int, buf []byte) (int, error) { if cLen > len(buf) { @@ -151,7 +131,7 @@ func (s *Conn) SetAlive(tp string) { } //set read deadline -func (s *Conn) SetReadDeadlineByType(t time.Duration, tp string) { +func (s *Conn) SetReadDeadlineBySecond(t time.Duration) { switch s.Conn.(type) { case *kcp.UDPSession: s.Conn.(*kcp.UDPSession).SetReadDeadline(time.Now().Add(time.Duration(t) * time.Second)) @@ -162,31 +142,9 @@ func (s *Conn) SetReadDeadlineByType(t time.Duration, tp string) { } } -//send info for link -func (s *Conn) SendLinkInfo(link *Link) (int, error) { - raw := bytes.NewBuffer([]byte{}) - common.BinaryWrite(raw, link.ConnType, link.Host, common.GetStrByBool(link.Compress), common.GetStrByBool(link.Crypt), link.RemoteAddr) - return s.Write(raw.Bytes()) -} - //get link info from conn func (s *Conn) GetLinkInfo() (lk *Link, err error) { - lk = new(Link) - var l int - buf := pool.BufPoolMax.Get().([]byte) - defer pool.PutBufPoolMax(buf) - if l, err = s.GetLen(); err != nil { - return - } else if _, err = s.ReadLen(l, buf); err != nil { - return - } else { - arr := strings.Split(string(buf[:l]), common.CONN_DATA_SEQ) - lk.ConnType = arr[0] - lk.Host = arr[1] - lk.Compress = common.GetBoolByStr(arr[2]) - lk.Crypt = common.GetBoolByStr(arr[3]) - lk.RemoteAddr = arr[4] - } + err = s.getInfo(&lk) return } @@ -215,95 +173,38 @@ func (s *Conn) GetHealthInfo() (info string, status bool, err error) { return "", false, errors.New("receive health info error") } -//send host info -func (s *Conn) SendHostInfo(h *file.Host) (int, error) { - /* - The task info is formed as follows: - +----+-----+---------+ - |type| len | content | - +----+---------------+ - | 4 | 4 | ... | - +----+---------------+ - */ - raw := bytes.NewBuffer([]byte{}) - binary.Write(raw, binary.LittleEndian, []byte(common.NEW_HOST)) - common.BinaryWrite(raw, h.Host, h.Target.TargetStr, h.HeaderChange, h.HostChange, h.Remark, h.Location, h.Scheme) - return s.Write(raw.Bytes()) -} - //get task info func (s *Conn) GetHostInfo() (h *file.Host, err error) { - var l int - buf := pool.BufPoolMax.Get().([]byte) - defer pool.PutBufPoolMax(buf) - if l, err = s.GetLen(); err != nil { - return - } else if _, err = s.ReadLen(l, buf); err != nil { - return - } else { - arr := strings.Split(string(buf[:l]), common.CONN_DATA_SEQ) - h = new(file.Host) - h.Target = new(file.Target) - h.Id = int(file.GetDb().JsonDb.GetHostId()) - h.Host = arr[0] - h.Target.TargetStr = arr[1] - h.HeaderChange = arr[2] - h.HostChange = arr[3] - h.Remark = arr[4] - h.Location = arr[5] - h.Scheme = arr[6] - if h.Scheme == "" { - h.Scheme = "all" - } - h.Flow = new(file.Flow) - h.NoStore = true - } + err = s.getInfo(&h) + h.Id = int(file.GetDb().JsonDb.GetHostId()) + h.Flow = new(file.Flow) + h.NoStore = true return } -//send task info -func (s *Conn) SendConfigInfo(c *config.CommonConfig) (int, error) { - /* - The task info is formed as follows: - +----+-----+---------+ - |type| len | content | - +----+---------------+ - | 4 | 4 | ... | - +----+---------------+ - */ - raw := bytes.NewBuffer([]byte{}) - binary.Write(raw, binary.LittleEndian, []byte(common.NEW_CONF)) - common.BinaryWrite(raw, c.Cnf.U, c.Cnf.P, common.GetStrByBool(c.Cnf.Crypt), common.GetStrByBool(c.Cnf.Compress), strconv.Itoa(c.Client.RateLimit), - strconv.Itoa(int(c.Client.Flow.FlowLimit)), strconv.Itoa(c.Client.MaxConn), c.Client.Remark) - return s.Write(raw.Bytes()) -} - //get task info func (s *Conn) GetConfigInfo() (c *file.Client, err error) { - var l int - buf := pool.BufPoolMax.Get().([]byte) - defer pool.PutBufPoolMax(buf) - if l, err = s.GetLen(); err != nil { - return - } else if _, err = s.ReadLen(l, buf); err != nil { - return - } else { - arr := strings.Split(string(buf[:l]), common.CONN_DATA_SEQ) - c = file.NewClient("", true, false) - c.Cnf.U = arr[0] - c.Cnf.P = arr[1] - c.Cnf.Crypt = common.GetBoolByStr(arr[2]) - c.Cnf.Compress = common.GetBoolByStr(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] + err = s.getInfo(&c) + c.NoStore = true + c.Status = true + if c.Flow == nil { + c.Flow = new(file.Flow) } + c.NoDisplay = false return } -//send task info -func (s *Conn) SendTaskInfo(t *file.Tunnel) (int, error) { +//get task info +func (s *Conn) GetTaskInfo() (t *file.Tunnel, err error) { + err = s.getInfo(&t) + t.Id = int(file.GetDb().JsonDb.GetTaskId()) + t.NoStore = true + t.Flow = new(file.Flow) + return +} + +//send info +func (s *Conn) SendInfo(t interface{}, flag string) (int, error) { /* The task info is formed as follows: +----+-----+---------+ @@ -313,13 +214,23 @@ 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.TargetStr, t.Remark, t.TargetAddr, t.Password, t.LocalPath, t.StripPre, t.ServerIp) + if flag != "" { + binary.Write(raw, binary.LittleEndian, []byte(flag)) + } + b, err := json.Marshal(t) + if err != nil { + return 0, err + } + lenBytes, err := GetLenBytes(b) + if err != nil { + return 0, err + } + binary.Write(raw, binary.LittleEndian, lenBytes) return s.Write(raw.Bytes()) } //get task info -func (s *Conn) GetTaskInfo() (t *file.Tunnel, err error) { +func (s *Conn) getInfo(t interface{}) (err error) { var l int buf := pool.BufPoolMax.Get().([]byte) defer pool.PutBufPoolMax(buf) @@ -328,24 +239,7 @@ func (s *Conn) GetTaskInfo() (t *file.Tunnel, err error) { } else if _, err = s.ReadLen(l, buf); err != nil { return } else { - arr := strings.Split(string(buf[:l]), common.CONN_DATA_SEQ) - t = new(file.Tunnel) - t.Target = new(file.Target) - t.Mode = arr[0] - t.Ports = arr[1] - t.Target.TargetStr = arr[2] - t.Id = int(file.GetDb().JsonDb.GetTaskId()) - t.Status = true - t.Flow = new(file.Flow) - t.Remark = arr[3] - t.TargetAddr = arr[4] - t.Password = arr[5] - t.LocalPath = arr[6] - t.StripPre = arr[7] - if len(arr) > 8 { - t.ServerIp = arr[8] - } - t.NoStore = true + json.Unmarshal(buf[:l], &t) } return } @@ -363,6 +257,7 @@ func (s *Conn) Write(b []byte) (int, error) { //read func (s *Conn) Read(b []byte) (n int, err error) { if s.Rb != nil { + //if the rb is not nil ,read rb first if len(s.Rb) > 0 { n = copy(b, s.Rb) s.Rb = s.Rb[n:] @@ -408,6 +303,26 @@ func (s *Conn) WriteAddFail() error { return binary.Write(s.Conn, binary.LittleEndian, false) } +func (s *Conn) LocalAddr() net.Addr { + return s.Conn.LocalAddr() +} + +func (s *Conn) RemoteAddr() net.Addr { + return s.Conn.RemoteAddr() +} + +func (s *Conn) SetDeadline(t time.Time) error { + return s.Conn.SetDeadline(t) +} + +func (s *Conn) SetWriteDeadline(t time.Time) error { + return s.Conn.SetWriteDeadline(t) +} + +func (s *Conn) SetReadDeadline(t time.Time) error { + return s.Conn.SetReadDeadline(t) +} + //get the assembled amount data(len 4 and content) func GetLenBytes(buf []byte) (b []byte, err error) { raw := bytes.NewBuffer([]byte{}) diff --git a/lib/file/db.go b/lib/file/db.go index 7de111c..7a611d5 100644 --- a/lib/file/db.go +++ b/lib/file/db.go @@ -215,8 +215,10 @@ reset: } if c.RateLimit == 0 { c.Rate = rate.NewRate(int64(2 << 23)) - c.Rate.Start() + } else if c.Rate == nil { + c.Rate = rate.NewRate(int64(c.RateLimit * 1024)) } + c.Rate.Start() if !s.VerifyVkey(c.VerifyKey, c.Id) { if isNotSet { goto reset diff --git a/lib/file/obj.go b/lib/file/obj.go index cbd916d..2895302 100644 --- a/lib/file/obj.go +++ b/lib/file/obj.go @@ -88,7 +88,7 @@ func (s *Client) GetConn() bool { func (s *Client) HasTunnel(t *Tunnel) (exist bool) { GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool { v := value.(*Tunnel) - if v.Client.Id == s.Id && v.Port == t.Port { + if v.Client.Id == s.Id && v.Port == t.Port && t.Port != 0 { exist = true return false } @@ -152,8 +152,8 @@ type Host struct { Location string //url router Remark string //remark Scheme string //http https all - CertFilePath string - KeyFilePath string + CertFilePath string + KeyFilePath string NoStore bool IsClose bool Flow *Flow diff --git a/server/proxy/https.go b/server/proxy/https.go index d2c160a..3a134a8 100644 --- a/server/proxy/https.go +++ b/server/proxy/https.go @@ -39,10 +39,7 @@ func (https *HttpsServer) Start() error { if v, ok := https.httpsListenerMap.Load(serverName); ok { l = v.(*HttpsListener) } else { - r := new(http.Request) - r.RequestURI = "/" - r.URL = new(url.URL) - r.URL.Scheme = "https" + r := buildHttpsRequest(serverName) if host, err := file.GetDb().GetInfoByHost(serverName, r); err != nil { c.Close() logs.Notice("the url %s can't be parsed!", serverName) @@ -50,7 +47,7 @@ func (https *HttpsServer) Start() error { } else { if !common.FileExists(host.CertFilePath) || !common.FileExists(host.KeyFilePath) { c.Close() - logs.Error("the key %s cert %s file is not exist", host.KeyFilePath, host.CertFilePath) + logs.Error("the key %s cert %s file is not exist", host.KeyFilePath, host.CertFilePath) return } l = NewHttpsListener(https.listener) @@ -79,11 +76,7 @@ func (https *HttpsServer) NewHttps(l net.Listener, certFile string, keyFile stri func (https *HttpsServer) handleHttps(c net.Conn) { hostName, rb := GetServerNameFromClientHello(c) var targetAddr string - r := new(http.Request) - r.RequestURI = "/" - r.URL = new(url.URL) - r.URL.Scheme = "https" - r.Host = hostName + r := buildHttpsRequest(hostName) var host *file.Host var err error if host, err = file.GetDb().GetInfoByHost(hostName, r); err != nil { @@ -145,3 +138,12 @@ func GetServerNameFromClientHello(c net.Conn) (string, []byte) { clientHello.Unmarshal(data[5:n]) return clientHello.GetServerName(), buf[:n] } + +func buildHttpsRequest(hostName string) *http.Request { + r := new(http.Request) + r.RequestURI = "/" + r.URL = new(url.URL) + r.URL.Scheme = "https" + r.Host = hostName + return r +}