瀏覽代碼

Url路由 泛解析

刘河 6 年之前
父節點
當前提交
9f6b33a62b

+ 1 - 1
README.md

@@ -326,7 +326,7 @@ nps.exe test|start|stop|restart|status
 - 服务端
 
 ```
-./nps -mode=tunnelServer -vkey=DKibZF5TXvic1g3kY -tcpport=8284 -httpport=8024 -target=10.1.50.203:80
+./nps -mode=tcpServer -vkey=DKibZF5TXvic1g3kY -tcpport=8284 -httpport=8024 -target=10.1.50.203:80
 ```
 
 名称 | 含义

+ 28 - 6
bridge/bridge.go

@@ -314,15 +314,37 @@ func (s *Bridge) GetConfig(c *conn.Conn) {
 				c.WriteAddFail()
 				break
 			} else {
-				t.Client = client
-				file.GetCsvDb().NewTask(t)
-				if b := tool.TestServerPort(t.Port, t.Mode); !b {
+				ports := common.GetPorts(t.Ports)
+				targets := common.GetPorts(t.Target)
+				if len(ports) > 1 && (t.Mode == "tcpServer" || t.Mode == "udpServer") && (len(ports) != len(targets)) {
 					fail = true
 					c.WriteAddFail()
-				} else {
-					s.OpenTask <- t
+					break
+				}
+				for i := 0; i < len(ports); i++ {
+					tl := new(file.Tunnel)
+					tl.Mode = t.Mode
+					tl.Port = ports[i]
+					if len(ports) == 1 {
+						tl.Target = t.Target
+					} else {
+						tl.Target = strconv.Itoa(targets[i])
+					}
+					tl.Id = file.GetCsvDb().GetTaskId()
+					tl.Status = true
+					tl.Flow = new(file.Flow)
+					tl.Remark = t.Remark
+					tl.NoStore = true
+					tl.Client = client
+					file.GetCsvDb().NewTask(tl)
+					if b := tool.TestServerPort(tl.Port, tl.Mode); !b {
+						fail = true
+						c.WriteAddFail()
+					} else {
+						s.OpenTask <- tl
+					}
+					c.WriteAddOk()
 				}
-				c.WriteAddOk()
 			}
 		}
 	}

+ 18 - 19
client/client.go

@@ -54,7 +54,9 @@ func (s *TRPClient) Close() {
 	s.tunnel.Close()
 	s.stop <- true
 	for _, v := range s.linkMap {
-		v.Stop <- true
+		if v.Conn != nil {
+			v.Conn.Close()
+		}
 	}
 }
 
@@ -74,7 +76,6 @@ func (s *TRPClient) processor(c *conn.Conn) {
 			if link, err := c.GetLinkInfo(); err != nil {
 				break
 			} else {
-				link.Stop = make(chan bool)
 				s.Lock()
 				s.linkMap[link.Id] = link
 				s.Unlock()
@@ -95,6 +96,7 @@ func (s *TRPClient) processor(c *conn.Conn) {
 }
 
 func (s *TRPClient) linkProcess(link *conn.Link, c *conn.Conn) {
+	link.Host = common.FormatAddress(link.Host)
 	//与目标建立连接
 	server, err := net.DialTimeout(link.ConnType, link.Host, time.Second*3)
 
@@ -106,26 +108,23 @@ func (s *TRPClient) linkProcess(link *conn.Link, c *conn.Conn) {
 
 	c.WriteSuccess(link.Id)
 
-	go func() {
-		link.Conn = conn.NewConn(server)
-		buf := pool.BufPoolCopy.Get().([]byte)
-		for {
-			if n, err := server.Read(buf); err != nil {
-				s.tunnel.SendMsg([]byte(common.IO_EOF), link)
+	link.Conn = conn.NewConn(server)
+	buf := pool.BufPoolCopy.Get().([]byte)
+	for {
+		if n, err := server.Read(buf); err != nil {
+			s.tunnel.SendMsg([]byte(common.IO_EOF), link)
+			break
+		} else {
+			if _, err := s.tunnel.SendMsg(buf[:n], link); err != nil {
+				c.Close()
 				break
-			} else {
-				if _, err := s.tunnel.SendMsg(buf[:n], link); err != nil {
-					c.Close()
-					break
-				}
 			}
 		}
-		pool.PutBufPoolCopy(buf)
-		s.Lock()
-		delete(s.linkMap, link.Id)
-		s.Unlock()
-	}()
-	<-link.Stop
+	}
+	pool.PutBufPoolCopy(buf)
+	s.Lock()
+	delete(s.linkMap, link.Id)
+	s.Unlock()
 }
 
 //隧道模式处理

+ 1 - 1
client/client_test.go

@@ -43,7 +43,7 @@ func TestConfig(t *testing.T) {
 	}
 	tunnel := &file.Tunnel{
 		Port: 9001,
-		Mode:    "tunnelServer",
+		Mode:    "tcpServer",
 		Target:  "127.0.0.1:8082",
 		Remark:  "333",
 	}

+ 1 - 1
conf/app.conf

@@ -37,4 +37,4 @@ bridgeType=tcp
 publicVkey=123
 
 #Open ports allowed on the server side
-allowPorts=9001-9009,10001,11000-12000
+allowPorts=9001-9100,10001,11000-12000

+ 1 - 0
conf/clients.csv

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

+ 1 - 0
conf/hosts.csv

@@ -0,0 +1 @@
+a.o.com,127.0.0.1:8080,7,,,,,1

+ 24 - 21
conf/npc.conf

@@ -2,32 +2,35 @@
 server=127.0.0.1:8284
 tp=tcp
 vkey=123
-username=111
-password=222
 compress=snappy
 crypt=true
 auto_reconnection=true
+
 [web1]
 host=a.o.com
-host_change=www.sina.com
-target=127.0.0.1:8080,127.0.0.1:8082
-header_cookkile=122123
-header_user-Agent=122123
+host_change=www.proxy.com
+target=127.0.0.1:8080
+
 [web2]
-host=www.baidu.com
-host_change=www.sina.com
+host=a.proxy.com
 target=127.0.0.1:8080,127.0.0.1:8082
-header_cookkile="122123"
-header_user-Agent=122123
-[tunnel1]
+host_change=www.proxy.com
+header_set_proxy=nps
+
+[tcp]
+mode=tcpServer
+target=8001-8005,8006
+port=9001-9005,9006
+
+[socks5]
+mode=socks5Server
+port=9007
+
+[http]
+mode=httpProxyServer
+port=9008
+
+[udp]
 mode=udpServer
-target=127.0.0.1:8080
-port=9001
-[tunnel2]
-mode=tunnelServer
-target=127.0.0.1:8080
-port=9001
-[tunnel3]
-mode=tunnelServer
-target=127.0.0.1:8080
-port=9002
+port=9009
+target=114.114.114.114:53

+ 41 - 1
lib/common/util.go

@@ -200,4 +200,44 @@ func InIntArr(arr []int, val int) bool {
 		}
 	}
 	return false
-}
+}
+
+func GetPorts(p string) []int {
+	var ps []int
+	arr := strings.Split(p, ",")
+	for _, v := range arr {
+		fw := strings.Split(v, "-")
+		if len(fw) == 2 {
+			if IsPort(fw[0]) && IsPort(fw[1]) {
+				start, _ := strconv.Atoi(fw[0])
+				end, _ := strconv.Atoi(fw[1])
+				for i := start; i <= end; i++ {
+					ps = append(ps, i)
+				}
+			} else {
+				continue
+			}
+		} else if IsPort(v) {
+			p, _ := strconv.Atoi(v)
+			ps = append(ps, p)
+		}
+	}
+	return ps
+}
+func IsPort(p string) bool {
+	pi, err := strconv.Atoi(p)
+	if err != nil {
+		return false
+	}
+	if pi > 65536 || pi < 1 {
+		return false
+	}
+	return true
+}
+
+func FormatAddress(s string) string {
+	if strings.Contains(s, ":") {
+		return s
+	}
+	return "127.0.0.1:" + s
+}

+ 1 - 1
lib/config/config.go

@@ -136,7 +136,7 @@ func dealTunnel(s string) *file.Tunnel {
 		}
 		switch item[0] {
 		case "port":
-			t.Port = common.GetIntNoErrByStr(item[1])
+			t.Ports = item[1]
 		case "mode":
 			t.Mode = item[1]
 		case "target":

+ 3 - 3
lib/conn/conn.go

@@ -82,7 +82,7 @@ func (s *Conn) ReadLen(cLen int) ([]byte, error) {
 		defer pool.BufPoolMax.Put(buf)
 	}
 	if n, err := io.ReadFull(s, buf); err != nil || n != cLen {
-		return buf, errors.New("读取指定长度错误" + err.Error())
+		return buf, errors.New("Error reading specified length" + err.Error())
 	}
 	return buf, nil
 }
@@ -368,7 +368,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, strconv.Itoa(t.Port), t.Target, t.Remark)
+	common.BinaryWrite(raw, t.Mode, t.Ports, t.Target, t.Remark)
 	s.Lock()
 	defer s.Unlock()
 	return s.Write(raw.Bytes())
@@ -386,7 +386,7 @@ func (s *Conn) GetTaskInfo() (t *file.Tunnel, err error) {
 		arr := strings.Split(string(b), common.CONN_DATA_SEQ)
 		t = new(file.Tunnel)
 		t.Mode = arr[0]
-		t.Port, _ = strconv.Atoi(arr[1])
+		t.Ports = arr[1]
 		t.Target = arr[2]
 		t.Id = file.GetCsvDb().GetTaskId()
 		t.Status = true

+ 0 - 1
lib/conn/link.go

@@ -18,7 +18,6 @@ type Link struct {
 	UdpListener   *net.UDPConn
 	Rate          *rate.Rate
 	UdpRemoteAddr *net.UDPAddr
-	Stop          chan bool
 }
 
 func NewLink(id int, connType string, host string, en, de int, crypt bool, c *Conn, flow *file.Flow, udpListener *net.UDPConn, rate *rate.Rate, UdpRemoteAddr *net.UDPAddr) *Link {

+ 62 - 11
lib/file/file.go

@@ -6,8 +6,10 @@ import (
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/lg"
 	"github.com/cnlh/nps/lib/rate"
+	"net/http"
 	"os"
 	"path/filepath"
+	"regexp"
 	"strconv"
 	"strings"
 	"sync"
@@ -27,6 +29,7 @@ type Csv struct {
 	RunPath          string    //存储根目录
 	ClientIncreaseId int       //客户端id
 	TaskIncreaseId   int       //任务自增ID
+	HostIncreaseId   int
 	sync.Mutex
 }
 
@@ -119,6 +122,12 @@ func (s *Csv) GetTaskId() int {
 	s.TaskIncreaseId++
 	return s.TaskIncreaseId
 }
+func (s *Csv) GetHostId() int {
+	s.Lock()
+	defer s.Unlock()
+	s.HostIncreaseId++
+	return s.HostIncreaseId
+}
 
 func (s *Csv) GetIdByVerifyKey(vKey string, addr string) (int, error) {
 	s.Lock()
@@ -195,6 +204,8 @@ func (s *Csv) StoreHostToCsv() {
 			host.HeaderChange,
 			host.HostChange,
 			host.Remark,
+			host.Location,
+			strconv.Itoa(host.Id),
 		}
 		err1 := writer.Write(record)
 		if err1 != nil {
@@ -256,19 +267,24 @@ func (s *Csv) LoadHostFromCsv() {
 			HeaderChange: item[3],
 			HostChange:   item[4],
 			Remark:       item[5],
+			Location:     item[6],
+			Id:           common.GetIntNoErrByStr(item[7]),
 		}
 		if post.Client, err = s.GetClient(common.GetIntNoErrByStr(item[2])); err != nil {
 			continue
 		}
 		post.Flow = new(Flow)
 		hosts = append(hosts, post)
+		if post.Id > s.HostIncreaseId {
+			s.HostIncreaseId = post.Id
+		}
 	}
 	s.Hosts = hosts
 }
 
-func (s *Csv) DelHost(host string) error {
+func (s *Csv) DelHost(id int) error {
 	for k, v := range s.Hosts {
-		if v.Host == host {
+		if v.Id == id {
 			s.Hosts = append(s.Hosts[:k], s.Hosts[k+1:]...)
 			s.StoreHostToCsv()
 			return nil
@@ -287,9 +303,6 @@ func (s *Csv) IsHostExist(host string) bool {
 }
 
 func (s *Csv) NewHost(t *Host) {
-	if s.IsHostExist(t.Host) {
-		return
-	}
 	t.Flow = new(Flow)
 	s.Hosts = append(s.Hosts, t)
 	s.StoreHostToCsv()
@@ -367,7 +380,7 @@ func (s *Csv) UpdateClient(t *Client) error {
 			return nil
 		}
 	}
-	return errors.New("不存在")
+	return errors.New("该客户端不存在")
 }
 
 func (s *Csv) GetClientList(start, length int) ([]*Client, int) {
@@ -407,16 +420,54 @@ func (s *Csv) GetClientIdByVkey(vkey string) (id int, err error) {
 	return
 }
 
-//get key by host from x
-func (s *Csv) GetInfoByHost(host string) (h *Host, err error) {
+func (s *Csv) GetHostById(id int) (h *Host, err error) {
 	for _, v := range s.Hosts {
-		s := strings.Split(host, ":")
-		if s[0] == v.Host {
+		if v.Id == id {
 			h = v
 			return
 		}
 	}
-	err = errors.New("未找到host对应的内网目标")
+	err = errors.New("The host could not be parsed")
+	return
+}
+
+//get key by host from x
+func (s *Csv) GetInfoByHost(host string, r *http.Request) (h *Host, err error) {
+	var hosts []*Host
+	for _, v := range s.Hosts {
+		//Remove http(s) http(s)://a.proxy.com
+		//*.proxy.com *.a.proxy.com  Do some pan-parsing
+		tmp := strings.Replace(v.Host, "*", `\w+?`, -1)
+		var re *regexp.Regexp
+		if re, err = regexp.Compile(tmp); err != nil {
+			return
+		}
+		if len(re.FindAllString(host, -1)) > 0 {
+			//URL routing
+			hosts = append(hosts, v)
+		}
+	}
+	for _, v := range hosts {
+		//If not set, default matches all
+		if v.Location == "" {
+			v.Location = "/"
+		}
+		if strings.Index(r.RequestURI, v.Location) == 0 {
+			if h == nil || (len(v.Location) > len(h.Location)) {
+				h = v
+			}
+		}
+	}
+	if h != nil {
+		if h.Location != "/" {
+			r.RequestURI = strings.Replace(r.RequestURI, h.Location, "", 1)
+		}
+		if r.RequestURI == "" {
+			r.RequestURI = "/"
+		}
+		return
+	}
+	err = errors.New("The host could not be parsed")
 	return
 }
 func (s *Csv) StoreClientsToCsv() {

+ 4 - 1
lib/file/obj.go

@@ -64,12 +64,13 @@ func (s *Client) GetId() int {
 
 type Tunnel struct {
 	Id        int     //Id
-	Port   int     //服务端监听端口
+	Port      int     //服务端监听端口
 	Mode      string  //启动方式
 	Target    string  //目标
 	Status    bool    //设置是否开启
 	RunStatus bool    //当前运行状态
 	Client    *Client //所属客户端id
+	Ports     string  //客户端与服务端传递
 	Flow      *Flow
 	Remark    string //备注
 	NoStore   bool
@@ -85,10 +86,12 @@ type Config struct {
 }
 
 type Host struct {
+	Id           int
 	Host         string //启动方式
 	Target       string //目标
 	HeaderChange string //host修改
 	HostChange   string //host修改
+	Location     string //url 路由
 	Flow         *Flow
 	Client       *Client
 	Remark       string //备注

+ 14 - 10
server/proxy/http.go

@@ -110,19 +110,22 @@ func (s *httpServer) handleTunneling(w http.ResponseWriter, r *http.Request) {
 func (s *httpServer) process(c *conn.Conn, r *http.Request) {
 	//多客户端域名代理
 	var (
-		isConn = true
-		lk     *conn.Link
-		host   *file.Host
-		tunnel *conn.Conn
-		err    error
+		isConn   = true
+		lk       *conn.Link
+		host     *file.Host
+		tunnel   *conn.Conn
+		lastHost *file.Host
+		err      error
 	)
 	for {
-		//首次获取conn
+		if host, err = file.GetCsvDb().GetInfoByHost(r.Host, r); err != nil {
+			lg.Printf("the url %s %s is not found !", r.Host, r.RequestURI)
+			break
+		} else if host != lastHost {
+			lastHost = host
+			isConn = true
+		}
 		if isConn {
-			if host, err = file.GetCsvDb().GetInfoByHost(r.Host); err != nil {
-				lg.Printf("the host %s is not found !", r.Host)
-				break
-			}
 			//流量限制
 			if host.Client.Flow.FlowLimit > 0 && (host.Client.Flow.FlowLimit<<20) < (host.Client.Flow.ExportFlow+host.Client.Flow.InletFlow) {
 				break
@@ -147,6 +150,7 @@ func (s *httpServer) process(c *conn.Conn, r *http.Request) {
 		//根据设定,修改header和host
 		common.ChangeHostAndHeader(r, host.HostChange, host.HeaderChange, c.Conn.RemoteAddr().String())
 		b, err := httputil.DumpRequest(r, true)
+		lg.Println(string(b), r.RequestURI)
 		if err != nil {
 			break
 		}

+ 2 - 8
server/proxy/socks5.go

@@ -49,7 +49,6 @@ const (
 
 type Sock5ModeServer struct {
 	server
-	isVerify bool
 	listener net.Listener
 }
 
@@ -208,12 +207,12 @@ func (s *Sock5ModeServer) handleConn(c net.Conn) {
 		c.Close()
 		return
 	}
-	if s.isVerify {
+	if s.task.Client.Cnf.U != "" && s.task.Client.Cnf.P != "" {
 		buf[1] = UserPassAuth
 		c.Write(buf)
 		if err := s.Auth(c); err != nil {
 			c.Close()
-			lg.Println("验证失败:", err)
+			lg.Println("Validation failed:", err)
 			return
 		}
 	} else {
@@ -289,10 +288,5 @@ func NewSock5ModeServer(bridge *bridge.Bridge, task *file.Tunnel) *Sock5ModeServ
 	s := new(Sock5ModeServer)
 	s.bridge = bridge
 	s.task = task
-	if s.task.Client.Cnf.U != "" && s.task.Client.Cnf.P != "" {
-		s.isVerify = true
-	} else {
-		s.isVerify = false
-	}
 	return s
 }

+ 14 - 11
server/server.go

@@ -69,7 +69,7 @@ func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string) {
 //new a server by mode name
 func NewMode(Bridge *bridge.Bridge, c *file.Tunnel) interface{} {
 	switch c.Mode {
-	case "tunnelServer":
+	case "tcpServer":
 		return proxy.NewTunnelModeServer(proxy.ProcessTunnel, Bridge, c)
 	case "socks5Server":
 		return proxy.NewSock5ModeServer(Bridge, c)
@@ -96,12 +96,15 @@ func NewMode(Bridge *bridge.Bridge, c *file.Tunnel) interface{} {
 //stop server
 func StopServer(id int) error {
 	if v, ok := RunList[id]; ok {
-		reflect.ValueOf(v).MethodByName("Close").Call(nil)
-		if t, err := file.GetCsvDb().GetTask(id); err != nil {
-			return err
-		} else {
-			t.Status = false
-			file.GetCsvDb().UpdateTask(t)
+		if reflect.ValueOf(v).IsValid() {
+			//TODO 错误处理
+			reflect.ValueOf(v).MethodByName("Close").Call(nil)
+			if t, err := file.GetCsvDb().GetTask(id); err != nil {
+				return err
+			} else {
+				t.Status = false
+				file.GetCsvDb().UpdateTask(t)
+			}
 		}
 		delete(RunList, id)
 		return nil
@@ -113,7 +116,7 @@ func StopServer(id int) error {
 func AddTask(t *file.Tunnel) error {
 	if b := tool.TestServerPort(t.Port, t.Mode); !b && t.Mode != "httpHostServer" {
 		lg.Printf("taskId %d start error Port %d Open Failed", t.Id, t.Port)
-		return errors.New("error")
+		return errors.New("the port open error")
 	}
 	if svr := NewMode(Bridge, t); svr != nil {
 		RunList[t.Id] = svr
@@ -226,7 +229,7 @@ func DelTunnelAndHostByClientId(clientId int) {
 	}
 	for _, v := range file.GetCsvDb().Hosts {
 		if v.Client.Id == clientId {
-			file.GetCsvDb().DelHost(v.Host)
+			file.GetCsvDb().DelHost(v.Id)
 		}
 	}
 }
@@ -256,8 +259,8 @@ func GetDashboardData() map[string]int {
 	data["exportFlowCount"] = int(out)
 	for _, v := range file.GetCsvDb().Tasks {
 		switch v.Mode {
-		case "tunnelServer":
-			data["tunnelServerCount"] += 1
+		case "tcpServer":
+			data["tcpServerCount"] += 1
 		case "socks5Server":
 			data["socks5ServerCount"] += 1
 		case "httpProxyServer":

+ 2 - 30
server/tool/utils.go

@@ -3,43 +3,15 @@ package tool
 import (
 	"github.com/cnlh/nps/lib/beego"
 	"github.com/cnlh/nps/lib/common"
-	"strconv"
-	"strings"
 )
 
 var ports []int
 
 func init() {
 	p := beego.AppConfig.String("allowPorts")
-	arr := strings.Split(p, ",")
-	for _, v := range arr {
-		fw := strings.Split(v, "-")
-		if len(fw) == 2 {
-			if isPort(fw[0]) && isPort(fw[1]) {
-				start, _ := strconv.Atoi(fw[0])
-				end, _ := strconv.Atoi(fw[1])
-				for i := start; i <= end; i++ {
-					ports = append(ports, i)
-				}
-			} else {
-				continue
-			}
-		} else if isPort(v) {
-			p, _ := strconv.Atoi(v)
-			ports = append(ports, p)
-		}
-	}
-}
-func isPort(p string) bool {
-	pi, err := strconv.Atoi(p)
-	if err != nil {
-		return false
-	}
-	if pi > 65536 || pi < 1 {
-		return false
-	}
-	return true
+	ports = common.GetPorts(p)
 }
+
 func TestServerPort(p int, m string) (b bool) {
 	if len(ports) != 0 {
 		if !common.InIntArr(ports, p) {

+ 1 - 1
web/controllers/client.go

@@ -103,7 +103,7 @@ func (s *ClientController) Edit() {
 			} else {
 				c.Rate = nil
 			}
-			file.GetCsvDb().UpdateClient(c)
+			file.GetCsvDb().StoreClientsToCsv()
 		}
 		s.AjaxOk("修改成功")
 	}

+ 18 - 15
web/controllers/index.go

@@ -21,7 +21,7 @@ func (s *IndexController) Help() {
 
 func (s *IndexController) Tcp() {
 	s.SetInfo("tcp隧道管理")
-	s.SetType("tunnelServer")
+	s.SetType("tcpServer")
 	s.display("index/list")
 }
 
@@ -73,13 +73,13 @@ func (s *IndexController) Add() {
 		s.display()
 	} else {
 		t := &file.Tunnel{
-			Port: s.GetIntNoErr("port"),
-			Mode:    s.GetString("type"),
-			Target:  s.GetString("target"),
-			Id:           file.GetCsvDb().GetTaskId(),
-			Status:       true,
-			Remark:       s.GetString("remark"),
-			Flow:         &file.Flow{},
+			Port:   s.GetIntNoErr("port"),
+			Mode:   s.GetString("type"),
+			Target: s.GetString("target"),
+			Id:     file.GetCsvDb().GetTaskId(),
+			Status: true,
+			Remark: s.GetString("remark"),
+			Flow:   &file.Flow{},
 		}
 		var err error
 		if t.Client, err = file.GetCsvDb().GetClient(s.GetIntNoErr("client_id")); err != nil {
@@ -175,7 +175,7 @@ func (s *IndexController) HostList() {
 func (s *IndexController) GetHost() {
 	if s.Ctx.Request.Method == "POST" {
 		data := make(map[string]interface{})
-		if h, err := file.GetCsvDb().GetInfoByHost(s.GetString("host")); err != nil {
+		if h, err := file.GetCsvDb().GetHostById(s.GetIntNoErr("id")); err != nil {
 			data["code"] = 0
 		} else {
 			data["data"] = h
@@ -187,8 +187,8 @@ func (s *IndexController) GetHost() {
 }
 
 func (s *IndexController) DelHost() {
-	host := s.GetString("host")
-	if err := file.GetCsvDb().DelHost(host); err != nil {
+	id := s.GetIntNoErr("id")
+	if err := file.GetCsvDb().DelHost(id); err != nil {
 		s.AjaxErr("删除失败")
 	}
 	s.AjaxOk("删除成功")
@@ -202,11 +202,13 @@ func (s *IndexController) AddHost() {
 		s.display("index/hadd")
 	} else {
 		h := &file.Host{
+			Id:           file.GetCsvDb().GetHostId(),
 			Host:         s.GetString("host"),
 			Target:       s.GetString("target"),
 			HeaderChange: s.GetString("header"),
 			HostChange:   s.GetString("hostchange"),
 			Remark:       s.GetString("remark"),
+			Location:     s.GetString("location"),
 			Flow:         &file.Flow{},
 		}
 		var err error
@@ -219,10 +221,10 @@ func (s *IndexController) AddHost() {
 }
 
 func (s *IndexController) EditHost() {
-	host := s.GetString("host")
+	id := s.GetIntNoErr("id")
 	if s.Ctx.Request.Method == "GET" {
 		s.Data["menu"] = "host"
-		if h, err := file.GetCsvDb().GetInfoByHost(host); err != nil {
+		if h, err := file.GetCsvDb().GetHostById(id); err != nil {
 			s.error()
 		} else {
 			s.Data["h"] = h
@@ -230,15 +232,16 @@ func (s *IndexController) EditHost() {
 		s.SetInfo("修改")
 		s.display("index/hedit")
 	} else {
-		if h, err := file.GetCsvDb().GetInfoByHost(host); err != nil {
+		if h, err := file.GetCsvDb().GetHostById(id); err != nil {
 			s.error()
 		} else {
-			h.Host = s.GetString("nhost")
+			h.Host = s.GetString("host")
 			h.Target = s.GetString("target")
 			h.HeaderChange = s.GetString("header")
 			h.HostChange = s.GetString("hostchange")
 			h.Remark = s.GetString("remark")
 			h.TargetArr = nil
+			h.Location = s.GetString("location")
 			file.GetCsvDb().UpdateHost(h)
 			var err error
 			if h.Client, err = file.GetCsvDb().GetClient(s.GetIntNoErr("client_id")); err != nil {

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

@@ -7,7 +7,7 @@
                     <div class="form-group">
                         <label class="control-label">模式</label>
                         <select class="form-control" name="type" id="type">
-                            <option {{if eq "tunnelServer" .type}}selected{{end}} value="tunnelServer">tcp隧道</option>
+                            <option {{if eq "tcpServer" .type}}selected{{end}} value="tcpServer">tcp隧道</option>
                             <option {{if eq "udpServer" .type}}selected{{end}} value="udpServer">udp隧道</option>
                             <option {{if eq "socks5Server" .type}}selected{{end}} value="socks5Server">socks5代理</option>
                             <option {{if eq "httpProxyServer" .type}}selected{{end}} value="httpProxyServer">http代理
@@ -44,7 +44,7 @@
 <script>
     var arr = []
     arr["all"] = ["type", "port", "compress", "u", "p", "target"]
-    arr["tunnelServer"] = ["type", "port", "target", "compress", "u", "p", "tcp隧道模式,提供一条tcp隧道,适用于ssh、远程桌面等,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,访问公网服务器的设定端口,则相当于访问内网目标地址的目标端口"]
+    arr["tcpServer"] = ["type", "port", "target", "compress", "u", "p", "tcp隧道模式,提供一条tcp隧道,适用于ssh、远程桌面等,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,访问公网服务器的设定端口,则相当于访问内网目标地址的目标端口"]
     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代理,即访问内网站点"]

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

@@ -8,7 +8,7 @@
                     <div class="form-group">
                         <label class="control-label">模式</label>
                         <select class="form-control" name="type" id="type">
-                            <option {{if eq "tunnelServer" .t.Mode}}selected{{end}} value="tunnelServer">tcp隧道</option>
+                            <option {{if eq "tcpServer" .t.Mode}}selected{{end}} value="tcpServer">tcp隧道</option>
                             <option {{if eq "udpServer" .t.Mode}}selected{{end}} value="udpServer">udp隧道</option>
                             <option {{if eq "socks5Server" .t.Mode}}selected{{end}} value="socks5Server">socks5代理
                             </option>
@@ -48,7 +48,7 @@
 <script>
     var arr = []
     arr["all"] = ["type", "port", "compress", "u", "p", "target"]
-    arr["tunnelServer"] = ["type", "port", "target", "u", "p", "compress"]
+    arr["tcpServer"] = ["type", "port", "target", "u", "p", "compress"]
     arr["udpServer"] = ["type", "port", "target", "compress"]
     arr["socks5Server"] = ["type", "port", "compress", "u", "p"]
     arr["httpProxyServer"] = ["type", "port", "compress", "u", "p"]

+ 4 - 0
web/views/index/hadd.html

@@ -12,6 +12,10 @@
                         <label class="control-label">域名</label>
                         <input class="form-control" type="text" name="host" placeholder="域名">
                     </div>
+                    <div class="form-group">
+                        <label class="control-label">URL路由(可忽略)</label>
+                        <input class="form-control" type="text" name="location" placeholder="URL路由">
+                    </div>
                     <div class="form-group">
                         <label class="control-label">客户端id</label>
                         <input value="{{.client_id}}" class="form-control" type="text" name="client_id"

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

@@ -4,10 +4,15 @@
             <h3 class="tile-title">修改</h3>
             <div class="tile-body">
                 <form>
+                    <input type="hidden" name="id" value="{{.h.Id}}">
                     <div class="form-group">
                         <label class="control-label">域名</label>
-                        <input class="form-control" value="{{.h.Host}}" type="hidden" name="host" placeholder="域名">
-                        <input class="form-control" value="{{.h.Host}}" type="text" name="nhost" placeholder="域名">
+                        <input class="form-control" value="{{.h.Host}}" name="host" placeholder="域名">
+                    </div>
+                    <div class="form-group">
+                        <label class="control-label">URL路由(可忽略)</label>
+                        <input class="form-control" value="{{.h.Location}}" type="text" name="location"
+                               placeholder="URL路由">
                     </div>
                     <div class="form-group">
                         <label class="control-label">备注</label>

+ 9 - 7
web/views/index/hlist.html

@@ -5,6 +5,7 @@
                 <table class="table table-hover table-bordered" id="sampleTable">
                     <thead>
                     <tr>
+                        <th>id</th>
                         <th>客户端id</th>
                         <th>备注</th>
                         <th>host</th>
@@ -30,12 +31,12 @@
 </main>
 
 <script type="text/javascript">
-    function del(host) {
+    function del(id) {
         if (confirm("确定要删除数据吗?")) {
             $.ajax({
                 type: "POST",
                 url: "/index/delhost",
-                data: {"host": host},
+                data: {"id": id},
                 success: function (res) {
                     alert(res.msg)
                     if (res.status) {
@@ -50,8 +51,8 @@
         window.location.href = "/index/addhost?vkey={{.task_id}}&client_id={{.client_id}}"
     }
 
-    function edit(host) {
-        window.location.href = "/index/edithost?host=" + host
+    function edit(id) {
+        window.location.href = "/index/edithost?id=" + id
     }
 
     $(document).ready(function () {
@@ -72,6 +73,7 @@
             },
             dom: '<"top"fl><"toolbar">rt<"bottom"ip><"clear">',
             columns: [ //这个是显示到界面上的个数据 格式为 {data:'显示的字段名'}
+                {data: 'Id'},
                 {data: 'Remark'},
                 {data: 'Remark'},
                 {data: 'Host'},
@@ -91,13 +93,13 @@
                 render: function (data, type, row, meta) {
 
                     return '<div class="btn-group" role="group" aria-label="..."> ' +
-                            '<button onclick="del(\'' + row.Host + '\')" type="button"   class="btn btn-danger btn-sm">删除</button>' +
-                            '<button onclick="edit(\'' + row.Host + '\')" type="button"   class="btn btn-primary btn-sm">编辑查看</button> '
+                            '<button onclick="del(\'' + row.Id + '\')" type="button"   class="btn btn-danger btn-sm">删除</button>' +
+                            '<button onclick="edit(\'' + row.Id + '\')" type="button"   class="btn btn-primary btn-sm">编辑查看</button> '
                             + ' </div>'
                 }
             },
                 {
-                    targets: 0,
+                    targets: 1,
                     render: function (data, type, row, meta) {
                         return row.Client.Id
                     }

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

@@ -107,7 +107,7 @@
                 radius : '55%',
                 center: ['50%', '60%'],
                 data:[
-                    {value:{{.data.tunnelServerCount}}, name:'tcp隧道数'},
+                    {value:{{.data.tcpServerCount}}, name:'tcp隧道数'},
                     {value:{{.data.socks5ServerCount}}, name:'socks5隧道数'},
                     {value:{{.data.httpProxyServerCount}}, name:'http隧道数'},
                     {value:{{.data.udpServerCount}}, name:'udp隧道数'},