Browse Source

public key bug and multiuser enhancement and server ip support and config file of client optimization

刘河 6 years ago
parent
commit
42a73fa392

+ 13 - 12
bridge/bridge.go

@@ -200,20 +200,28 @@ func (s *Bridge) cliProcess(c *conn.Conn) {
 
 func (s *Bridge) DelClient(id int) {
 	if v, ok := s.Client.Load(id); ok {
-		if c, err := file.GetCsvDb().GetClient(id); err == nil && c.NoStore {
-			s.CloseClient <- c.Id
-		}
 		if v.(*Client).signal != nil {
 			v.(*Client).signal.Close()
 		}
 		s.Client.Delete(id)
+		if file.GetCsvDb().IsPubClient(id) {
+			return
+		}
+		if c, err := file.GetCsvDb().GetClient(id); err == nil && c.NoStore {
+			s.CloseClient <- c.Id
+		}
 	}
 }
 
 //use different
 func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int) {
+	isPub := file.GetCsvDb().IsPubClient(id)
 	switch typeVal {
 	case common.WORK_MAIN:
+		if isPub {
+			c.Close()
+			return
+		}
 		//the vKey connect by another ,close the client of before
 		if v, ok := s.Client.LoadOrStore(id, NewClient(nil, nil, c)); ok {
 			if v.(*Client).signal != nil {
@@ -229,16 +237,8 @@ func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int) {
 			v.(*Client).tunnel = muxConn
 		}
 	case common.WORK_CONFIG:
-		var isPub bool
 		client, err := file.GetCsvDb().GetClient(id)
-		if err == nil {
-			if client.VerifyKey == beego.AppConfig.String("public_vkey") {
-				isPub = true
-			} else {
-				isPub = false
-			}
-		}
-		if !isPub && !client.ConfigConnAllow {
+		if err != nil || (!isPub && !client.ConfigConnAllow) {
 			c.Close()
 			return
 		}
@@ -458,6 +458,7 @@ loop:
 					tl := new(file.Tunnel)
 					tl.Mode = t.Mode
 					tl.Port = ports[i]
+					tl.ServerIp = t.ServerIp
 					if len(ports) == 1 {
 						tl.Target = t.Target
 						tl.Remark = t.Remark

+ 9 - 3
client/client.go

@@ -228,7 +228,13 @@ loop:
 }
 
 func (s *TRPClient) Close() {
-	s.tunnel.Close()
-	s.signal.Close()
-	s.ticker.Stop()
+	if s.tunnel != nil {
+		s.tunnel.Close()
+	}
+	if s.signal != nil {
+		s.signal.Close()
+	}
+	if s.ticker != nil {
+		s.ticker.Stop()
+	}
 }

+ 15 - 16
conf/npc.conf

@@ -1,7 +1,7 @@
 [common]
-server=127.0.0.1:8024
-tp=tcp
-vkey=123
+server_addr=127.0.0.1:8024
+conn_type=tcp
+vkey=nps
 auto_reconnection=true
 
 [health_check_test1]
@@ -20,39 +20,38 @@ health_check_type=tcp
 health_check_target=127.0.0.1:8083,127.0.0.1:8082
 [web]
 host=b.o.com
-target=127.0.0.1:8080
+target_addr=127.0.0.1:8080
 
 [tcp]
 mode=tcp
-target=127.0.0.1:8083,127.0.0.1:8082
-port=9006
-targetAddr=123.206.77.88
+target=127.0.0.1:8080
+server_port=10000
 
 [socks5]
 mode=socks5
-port=9005
+server_port=9005
 
 [http]
 mode=httpProxy
-port=9004
+server_port=9004
 
 
 [file]
 mode=file
-port=9009
+server_port=9009
 local_path=./
 strip_pre=/web/
 
 [udp]
 mode=udp
-port=53
-target=114.114.114.114:53
+server_port=53
+target_addr=114.114.114.114:53
 
 [secret_ssh]
-port=2001
+local_port=2001
 password=sec
 
 [p2p_ssh]
-port=2002
-password=c
-target=123.206.77.88:22
+local_port=2002
+password=ppp
+target_addr=192.168.74.199:22

+ 1 - 0
conf/nps.conf

@@ -6,6 +6,7 @@ runmode = pro
 http_proxy_port=80
 https_proxy_port=443
 https_just_proxy=true
+http_proxy_ip=0.0.0.0
 #certFile absolute path
 #pem_path=conf/server.pem
 #KeyFile absolute path

+ 1 - 1
conf/tasks.csv

@@ -1 +1 @@
-9988,tcp,127.0.0.1:8080,1,3,11,,0,504,
+9999,tcp,,1,3,11,,0,0,,0.0.0.0

+ 13 - 8
lib/config/config.go

@@ -20,6 +20,7 @@ type CommonConfig struct {
 type LocalServer struct {
 	Type     string
 	Port     int
+	Ip       string
 	Password string
 	Target   string
 }
@@ -112,11 +113,11 @@ func dealCommon(s string) *CommonConfig {
 			item = append(item, "")
 		}
 		switch item[0] {
-		case "server":
+		case "server_addr":
 			c.Server = item[1]
 		case "vkey":
 			c.VKey = item[1]
-		case "tp":
+		case "conn_type":
 			c.Tp = item[1]
 		case "auto_reconnection":
 			c.AutoReconnection = common.GetBoolByStr(item[1])
@@ -156,7 +157,7 @@ func dealHost(s string) *file.Host {
 		switch strings.TrimSpace(item[0]) {
 		case "host":
 			h.Host = item[1]
-		case "target":
+		case "target_addr":
 			h.Target = strings.Replace(item[1], ",", "\n", -1)
 		case "host_change":
 			h.HostChange = item[1]
@@ -211,13 +212,15 @@ func dealTunnel(s string) *file.Tunnel {
 			item = append(item, "")
 		}
 		switch strings.TrimSpace(item[0]) {
-		case "port":
+		case "server_port":
 			t.Ports = item[1]
+		case "server_ip":
+			t.ServerIp = item[1]
 		case "mode":
 			t.Mode = item[1]
-		case "target":
+		case "target_port", "target_addr":
 			t.Target = strings.Replace(item[1], ",", "\n", -1)
-		case "targetAddr":
+		case "target_ip":
 			t.TargetAddr = item[1]
 		case "password":
 			t.Password = item[1]
@@ -241,11 +244,13 @@ func delLocalService(s string) *LocalServer {
 			item = append(item, "")
 		}
 		switch item[0] {
-		case "port":
+		case "local_port":
 			l.Port = common.GetIntNoErrByStr(item[1])
+		case "local_ip":
+			l.Ip = item[1]
 		case "password":
 			l.Password = item[1]
-		case "target":
+		case "target_addr":
 			l.Target = item[1]
 		}
 	}

+ 4 - 1
lib/conn/conn.go

@@ -316,7 +316,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, t.TargetAddr, t.Password, t.LocalPath, t.StripPre)
+	common.BinaryWrite(raw, t.Mode, t.Ports, t.Target, t.Remark, t.TargetAddr, t.Password, t.LocalPath, t.StripPre, t.ServerIp)
 	s.Lock()
 	defer s.Unlock()
 	return s.Write(raw.Bytes())
@@ -345,6 +345,9 @@ func (s *Conn) GetTaskInfo() (t *file.Tunnel, err error) {
 		t.Password = arr[5]
 		t.LocalPath = arr[6]
 		t.StripPre = arr[7]
+		if len(arr) > 8 {
+			t.ServerIp = arr[8]
+		}
 		t.NoStore = true
 	}
 	return

+ 23 - 1
lib/file/file.go

@@ -7,6 +7,7 @@ import (
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/crypt"
 	"github.com/cnlh/nps/lib/rate"
+	"github.com/cnlh/nps/vender/github.com/astaxie/beego"
 	"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
 	"net/http"
 	"os"
@@ -59,6 +60,7 @@ func (s *Csv) StoreTasksToCsv() {
 			strconv.Itoa(int(task.Flow.ExportFlow)),
 			strconv.Itoa(int(task.Flow.InletFlow)),
 			task.Password,
+			task.ServerIp,
 		}
 		err := writer.Write(record)
 		if err != nil {
@@ -111,6 +113,11 @@ func (s *Csv) LoadTaskFromCsv() {
 		if post.Client, err = s.GetClient(common.GetIntNoErrByStr(item[5])); err != nil {
 			continue
 		}
+		if len(item) > 10 {
+			post.ServerIp = item[10]
+		} else {
+			post.ServerIp = "0.0.0.0"
+		}
 		s.Tasks.Store(post.Id, post)
 		if post.Id > int(s.TaskIncreaseId) {
 			s.TaskIncreaseId = int32(s.TaskIncreaseId)
@@ -440,7 +447,7 @@ func (s *Csv) UpdateClient(t *Client) error {
 	return nil
 }
 
-func (s *Csv) GetClientList(start, length int, search string) ([]*Client, int) {
+func (s *Csv) GetClientList(start, length int, search string, clientId int) ([]*Client, int) {
 	list := make([]*Client, 0)
 	var cnt int
 	keys := common.GetMapKeys(s.Clients)
@@ -450,6 +457,9 @@ func (s *Csv) GetClientList(start, length int, search string) ([]*Client, int) {
 			if v.NoDisplay {
 				continue
 			}
+			if clientId != 0 && clientId != v.Id {
+				continue
+			}
 			if search != "" && !(v.Id == common.GetIntNoErrByStr(search) || strings.Contains(v.VerifyKey, search) || strings.Contains(v.Remark, search)) {
 				continue
 			}
@@ -464,6 +474,18 @@ func (s *Csv) GetClientList(start, length int, search string) ([]*Client, int) {
 	return list, cnt
 }
 
+func (s *Csv) IsPubClient(id int) bool {
+	client, err := s.GetClient(id)
+	if err == nil {
+		if client.VerifyKey == beego.AppConfig.String("public_vkey") {
+			return true
+		} else {
+			return false
+		}
+	}
+	return false
+}
+
 func (s *Csv) GetClient(id int) (c *Client, err error) {
 	if v, ok := s.Clients.Load(id); ok {
 		c = v.(*Client)

+ 3 - 2
lib/file/obj.go

@@ -111,8 +111,9 @@ func (s *Client) HasHost(h *Host) bool {
 }
 
 type Tunnel struct {
-	Id         int      //Id
-	Port       int      //服务端监听端口
+	Id         int //Id
+	Port       int //服务端监听端口
+	ServerIp   string
 	Mode       string   //启动方式
 	Target     string   //目标
 	TargetArr  []string //目标

+ 1 - 1
lib/version/version.go

@@ -1,6 +1,6 @@
 package version
 
-const VERSION = "0.20.0"
+const VERSION = "0.20.1"
 
 // Compulsory minimum version, Minimum downward compatibility to this version
 func GetVersion() string {

+ 2 - 2
server/connection/connection.go

@@ -50,7 +50,7 @@ func GetHttpListener() (net.Listener, error) {
 		return pMux.GetHttpListener(), nil
 	}
 	logs.Info("start http listener, port is", httpPort)
-	return getTcpListener("", httpPort)
+	return getTcpListener(beego.AppConfig.String("http_proxy_ip"), httpPort)
 }
 
 func GetHttpsListener() (net.Listener, error) {
@@ -59,7 +59,7 @@ func GetHttpsListener() (net.Listener, error) {
 		return pMux.GetHttpsListener(), nil
 	}
 	logs.Info("start https listener, port is", httpsPort)
-	return getTcpListener("", httpsPort)
+	return getTcpListener(beego.AppConfig.String("http_proxy_ip"), httpsPort)
 }
 
 func GetWebManagerListener() (net.Listener, error) {

+ 1 - 1
server/proxy/socks5.go

@@ -251,7 +251,7 @@ func (s *Sock5ModeServer) Auth(c net.Conn) error {
 
 //start
 func (s *Sock5ModeServer) Start() error {
-	return conn.NewTcpListenerAndProcess(":"+strconv.Itoa(s.task.Port), func(c net.Conn) {
+	return conn.NewTcpListenerAndProcess(s.task.ServerIp+":"+strconv.Itoa(s.task.Port), func(c net.Conn) {
 		if err := s.CheckFlowAndConnNum(s.task.Client); err != nil {
 			logs.Warn("client id %d, task id %d, error %s, when socks5 connection", s.task.Client.Id, s.task.Id, err.Error())
 			c.Close()

+ 1 - 1
server/proxy/tcp.go

@@ -32,7 +32,7 @@ func NewTunnelModeServer(process process, bridge *bridge.Bridge, task *file.Tunn
 
 //开始
 func (s *TunnelModeServer) Start() error {
-	return conn.NewTcpListenerAndProcess(":"+strconv.Itoa(s.task.Port), func(c net.Conn) {
+	return conn.NewTcpListenerAndProcess(s.task.ServerIp+":"+strconv.Itoa(s.task.Port), func(c net.Conn) {
 		if err := s.CheckFlowAndConnNum(s.task.Client); err != nil {
 			logs.Warn("client id %d, task id %d,error %s, when tcp connection", s.task.Client.Id, s.task.Id, err.Error())
 			c.Close()

+ 4 - 1
server/proxy/udp.go

@@ -26,7 +26,10 @@ func NewUdpModeServer(bridge *bridge.Bridge, task *file.Tunnel) *UdpModeServer {
 //开始
 func (s *UdpModeServer) Start() error {
 	var err error
-	s.listener, err = net.ListenUDP("udp", &net.UDPAddr{net.ParseIP("0.0.0.0"), s.task.Port, ""})
+	if s.task.ServerIp == "" {
+		s.task.ServerIp = "0.0.0.0"
+	}
+	s.listener, err = net.ListenUDP("udp", &net.UDPAddr{net.ParseIP(s.task.ServerIp), s.task.Port, ""})
 	if err != nil {
 		return err
 	}

+ 2 - 2
server/server.go

@@ -255,8 +255,8 @@ func GetTunnel(start, length int, typeVal string, clientId int, search string) (
 }
 
 //获取客户端列表
-func GetClientList(start, length int, search string) (list []*file.Client, cnt int) {
-	list, cnt = file.GetCsvDb().GetClientList(start, length, search)
+func GetClientList(start, length int, search string, clientId int) (list []*file.Client, cnt int) {
+	list, cnt = file.GetCsvDb().GetClientList(start, length, search, clientId)
 	dealClientData()
 	return
 }

+ 10 - 1
web/controllers/base.go

@@ -140,7 +140,16 @@ func (s *BaseController) SetType(name string) {
 
 func (s *BaseController) CheckUserAuth() {
 	if s.controllerName == "client" {
-		s.StopRun()
+		if s.actionName == "add" {
+			s.StopRun()
+			return
+		}
+		if id := s.GetIntNoErr("id"); id != 0 {
+			if id != s.GetSession("clientId").(int) {
+				s.StopRun()
+				return
+			}
+		}
 	}
 	if s.controllerName == "index" {
 		if id := s.GetIntNoErr("id"); id != 0 {

+ 8 - 1
web/controllers/client.go

@@ -19,7 +19,14 @@ func (s *ClientController) List() {
 		return
 	}
 	start, length := s.GetAjaxParams()
-	list, cnt := server.GetClientList(start, length, s.GetString("search"))
+	clientIdSession := s.GetSession("clientId")
+	var clientId int
+	if clientIdSession == nil {
+		clientId = 0
+	} else {
+		clientId = clientIdSession.(int)
+	}
+	list, cnt := server.GetClientList(start, length, s.GetString("search"), clientId)
 	s.AjaxTable(list, cnt, cnt)
 }
 

+ 8 - 2
web/controllers/index.go

@@ -91,6 +91,7 @@ func (s *IndexController) Add() {
 	} else {
 		t := &file.Tunnel{
 			Port:      s.GetIntNoErr("port"),
+			ServerIp:  s.GetString("server_ip"),
 			Mode:      s.GetString("type"),
 			Target:    s.GetString("target"),
 			Id:        int(file.GetCsvDb().GetTaskId()),
@@ -144,7 +145,12 @@ func (s *IndexController) Edit() {
 		if t, err := file.GetCsvDb().GetTask(id); err != nil {
 			s.error()
 		} else {
-			t.Port = s.GetIntNoErr("port")
+			var portChange bool
+			if s.GetIntNoErr("port") != t.Port {
+				portChange = true
+				t.Port = s.GetIntNoErr("port")
+			}
+			t.ServerIp = s.GetString("server_ip")
 			t.Mode = s.GetString("type")
 			t.Target = s.GetString("target")
 			t.Password = s.GetString("password")
@@ -152,7 +158,7 @@ func (s *IndexController) Edit() {
 			t.LocalPath = s.GetString("local_path")
 			t.StripPre = s.GetString("strip_pre")
 			t.Remark = s.GetString("remark")
-			if !tool.TestServerPort(t.Port, t.Mode) {
+			if portChange && !tool.TestServerPort(t.Port, t.Mode) {
 				s.AjaxErr("The port cannot be opened because it may has been occupied or is no longer allowed.")
 			}
 			if t.Client, err = file.GetCsvDb().GetClient(s.GetIntNoErr("client_id")); err != nil {

+ 14 - 10
web/views/client/list.html

@@ -15,15 +15,18 @@
                         </a>
                     </div>
                 </div>
-                <div class="content">
-                    <div class="table-responsive">
-                        <div id="toolbar">
-                            <a href="/client/add" class="btn btn-primary dim" type="button" langtag="info-new">新增</a>
-                        </div>
-                        <table id="taskList_table" class="table-striped table-hover"
-                               data-mobile-responsive="true"></table>
+            <div class="content">
+            {{if eq true .isAdmin}}
+
+                <div class="table-responsive">
+                    <div id="toolbar">
+                        <a href="/client/add" class="btn btn-primary dim" type="button" langtag="info-new">新增</a>
                     </div>
+                    <table id="taskList_table" class="table-striped table-hover"
+                           data-mobile-responsive="true"></table>
                 </div>
+            </div>
+            {{end}}
                 <div class="ibox-content">
 
                     <table id="table"></table>
@@ -225,11 +228,12 @@
                 sortable: true,//启用排序
                 formatter: function (value, row, index) {
                     btn_group = '<div class="btn-group">'
-                    btn = `<button onclick="del(` + row.Id + `)" class="btn-danger"><i class="fa fa-trash"></i></button><button onclick="edit(` + row.Id + `)" class="btn-primary"><i class="fa fa-edit"></i></button></div>`
+                    btn = ` {{if eq true .isAdmin}}<button onclick="del(` + row.Id + `)" class="btn-danger"><i class="fa fa-trash"></i></button>{{end}}<button onclick="edit(` + row.Id + `)" class="btn-primary"><i class="fa fa-edit"></i></button></div>`
+
                     if (row.Status) {
-                        return btn_group + `<button onclick="stop(` + row.Id + `)" class="btn-warning"><i class="fa fa-close"></i></button>` + btn
+                        return btn_group  {{if eq true .isAdmin}}+ `<button onclick="stop(` + row.Id + `)" class="btn-warning"><i class="fa fa-close"></i></button>` {{end}}+ btn
                     } else {
-                        return btn_group + `<button onclick="start(` + row.Id + `)" class="btn-warning"><i class="fa fa-check"></i></button>` + btn
+                        return btn_group  {{if eq true .isAdmin}}+ `<button onclick="start(` + row.Id + `)" class="btn-warning"><i class="fa fa-check"></i></button>` {{end}}+ btn
                     }
                 }
             },

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

@@ -28,6 +28,14 @@
                         </div>
                     </div>
 
+                    <div class="form-group" id="server_ip">
+                        <label class="col-sm-2 control-label" langtag="info-server-ip">服务端ip</label>
+                        <div class="col-sm-10">
+                            <input class="form-control" type="text" value="0.0.0.0" name="server_ip"
+                                   placeholder="such as 0.0.0.0">
+                        </div>
+                    </div>
+
                     <div class="form-group" id="port">
                         <label class="col-sm-2 control-label" langtag="info-server-port">服务端端口</label>
                         <div class="col-sm-10">

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

@@ -28,7 +28,13 @@
                                    placeholder="empty means to be unrestricted">
                         </div>
                     </div>
-
+                    <div class="form-group" id="server_ip">
+                        <label class="col-sm-2 control-label" langtag="info-server-ip">服务端ip</label>
+                        <div class="col-sm-10">
+                            <input class="form-control" type="text" value="{{.t.ServerIp}}" name="server_ip"
+                                   placeholder="such as 0.0.0.0">
+                        </div>
+                    </div>
                     <div class="form-group" id="port">
                         <label class="col-sm-2 control-label" langtag="info-server-port">服务端端口</label>
                         <div class="col-sm-10">

+ 7 - 3
web/views/public/layout.html

@@ -38,7 +38,13 @@
                     {{/*<img alt="image" class="img-circle" src="/static/img/profile_small.jpg"/>*/}}
                     </span>
                         <a href="#">
-                            <span class="clear"> <span class="block m-t-xs"> <strong class="font-bold">admin</strong>
+                            <span class="clear"> <span class="block m-t-xs"> <strong class="font-bold">
+                            {{if eq true .isAdmin}}
+                                admin
+                            {{else}}
+                                user
+                            {{end}}
+                            </strong>
                              </span> <span class="text-muted text-xs block">system </span> </span>
                         </a>
                     </div>
@@ -46,7 +52,6 @@
                         NPS
                     </div>
                 </li>
-            {{if eq true .isAdmin}}
                 <li class="{{if eq "index" .menu}}active{{end}}">
                     <a href="/"><i class="fa fa-dashboard"></i> <span langtag="menu-dashboard"
                                                                       class="nav-label">仪表盘</span></a>
@@ -55,7 +60,6 @@
                     <a href="/client/list"><i class="fa fa-clipboard"></i> <span langtag="menu-client"
                                                                                  class="nav-label">客户端</span></a>
                 </li>
-            {{end}}
                 <li class="{{if eq "host" .menu}}active{{end}}">
                     <a href="/index/hostlist"><i class="fa fa-paperclip"></i> <span langtag="menu-host"
                                                                                     class="nav-label">域名解析</span></a>