diff --git a/bridge/bridge.go b/bridge/bridge.go index 93feb45b..b42e32de 100755 --- a/bridge/bridge.go +++ b/bridge/bridge.go @@ -90,7 +90,7 @@ func (s *Bridge) GetHealthFromClient(id int, c *conn.Conn) { if info, status, err := c.GetHealthInfo(); err != nil { break } else if !status { //the status is true , return target to the targetArr - file.GetCsvDb().Tasks.Range(func(key, value interface{}) bool { + file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool { v := value.(*file.Tunnel) if v.Client.Id == id && v.Mode == "tcp" && strings.Contains(v.Target.TargetStr, info) { v.Lock() @@ -106,7 +106,7 @@ func (s *Bridge) GetHealthFromClient(id int, c *conn.Conn) { } return true }) - file.GetCsvDb().Hosts.Range(func(key, value interface{}) bool { + file.GetDb().JsonDb.Hosts.Range(func(key, value interface{}) bool { v := value.(*file.Host) if v.Client.Id == id && strings.Contains(v.Target.TargetStr, info) { v.Lock() @@ -123,7 +123,7 @@ func (s *Bridge) GetHealthFromClient(id int, c *conn.Conn) { return true }) } else { //the status is false,remove target from the targetArr - file.GetCsvDb().Tasks.Range(func(key, value interface{}) bool { + file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool { v := value.(*file.Tunnel) if v.Client.Id == id && v.Mode == "tcp" && common.IsArrContains(v.HealthRemoveArr, info) && !common.IsArrContains(v.Target.TargetArr, info) { v.Lock() @@ -134,7 +134,7 @@ func (s *Bridge) GetHealthFromClient(id int, c *conn.Conn) { return true }) - file.GetCsvDb().Hosts.Range(func(key, value interface{}) bool { + file.GetDb().JsonDb.Hosts.Range(func(key, value interface{}) bool { v := value.(*file.Host) if v.Client.Id == id && common.IsArrContains(v.HealthRemoveArr, info) && !common.IsArrContains(v.Target.TargetArr, info) { v.Lock() @@ -182,7 +182,7 @@ func (s *Bridge) cliProcess(c *conn.Conn) { return } //verify - id, err := file.GetCsvDb().GetIdByVerifyKey(string(buf), c.Conn.RemoteAddr().String()) + id, err := file.GetDb().GetIdByVerifyKey(string(buf), c.Conn.RemoteAddr().String()) if err != nil { logs.Info("Current client connection validation error, close this client:", c.Conn.RemoteAddr()) s.verifyError(c) @@ -204,10 +204,10 @@ func (s *Bridge) DelClient(id int) { v.(*Client).signal.Close() } s.Client.Delete(id) - if file.GetCsvDb().IsPubClient(id) { + if file.GetDb().IsPubClient(id) { return } - if c, err := file.GetCsvDb().GetClient(id); err == nil { + if c, err := file.GetDb().GetClient(id); err == nil { s.CloseClient <- c.Id } } @@ -215,7 +215,7 @@ func (s *Bridge) DelClient(id int) { //use different func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int) { - isPub := file.GetCsvDb().IsPubClient(id) + isPub := file.GetDb().IsPubClient(id) switch typeVal { case common.WORK_MAIN: if isPub { @@ -237,7 +237,7 @@ func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int) { v.(*Client).tunnel = muxConn } case common.WORK_CONFIG: - client, err := file.GetCsvDb().GetClient(id) + client, err := file.GetDb().GetClient(id) if err != nil || (!isPub && !client.ConfigConnAllow) { c.Close() return @@ -259,7 +259,7 @@ func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int) { //read md5 secret if b, err := c.GetShortContent(32); err != nil { return - } else if t := file.GetCsvDb().GetTaskByMd5Password(string(b)); t == nil { + } else if t := file.GetDb().GetTaskByMd5Password(string(b)); t == nil { return } else { if v, ok := s.Client.Load(t.Client.Id); !ok { @@ -373,18 +373,18 @@ loop: break loop } else { var str string - id, err := file.GetCsvDb().GetClientIdByVkey(string(b)) + id, err := file.GetDb().GetClientIdByVkey(string(b)) if err != nil { break loop } - file.GetCsvDb().Hosts.Range(func(key, value interface{}) bool { + file.GetDb().JsonDb.Hosts.Range(func(key, value interface{}) bool { v := value.(*file.Host) if v.Client.Id == id { str += v.Remark + common.CONN_DATA_SEQ } return true }) - file.GetCsvDb().Tasks.Range(func(key, value interface{}) bool { + file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool { v := value.(*file.Tunnel) if _, ok := s.runList[v.Id]; ok && v.Client.Id == id { str += v.Remark + common.CONN_DATA_SEQ @@ -401,7 +401,7 @@ loop: c.WriteAddFail() break loop } else { - if err = file.GetCsvDb().NewClient(client); err != nil { + if err = file.GetDb().NewClient(client); err != nil { fail = true c.WriteAddFail() break loop @@ -422,12 +422,12 @@ loop: h.Location = "/" } if !client.HasHost(h) { - if file.GetCsvDb().IsHostExist(h) { + if file.GetDb().IsHostExist(h) { fail = true c.WriteAddFail() break loop } else { - file.GetCsvDb().NewHost(h) + file.GetDb().NewHost(h) c.WriteAddOk() } } else { @@ -469,7 +469,7 @@ loop: tl.Target.TargetStr = strconv.Itoa(targets[i]) } } - tl.Id = int(file.GetCsvDb().GetTaskId()) + tl.Id = int(file.GetDb().JsonDb.GetTaskId()) tl.Status = true tl.Flow = new(file.Flow) tl.NoStore = true @@ -478,7 +478,7 @@ loop: tl.LocalPath = t.LocalPath tl.StripPre = t.StripPre if !client.HasTunnel(tl) { - if err := file.GetCsvDb().NewTask(tl); err != nil { + if err := file.GetDb().NewTask(tl); err != nil { logs.Notice("Add task error ", err.Error()) fail = true c.WriteAddFail() diff --git a/lib/common/util.go b/lib/common/util.go index 4b7bf00f..14365d68 100755 --- a/lib/common/util.go +++ b/lib/common/util.go @@ -15,6 +15,7 @@ import ( "regexp" "strconv" "strings" + "sync" ) //Get the corresponding IP address through domain name @@ -344,3 +345,12 @@ func BytesToNum(b []byte) int { x, _ := strconv.Atoi(str) return int(x) } + +func GeSynctMapLen(m sync.Map) int { + var c int + m.Range(func(key, value interface{}) bool { + c++ + return true + }) + return c +} diff --git a/lib/config/config.go b/lib/config/config.go index 0576398f..d9e7f4cc 100644 --- a/lib/config/config.go +++ b/lib/config/config.go @@ -93,7 +93,6 @@ func NewConfig(path string) (c *Config, err error) { } } } - } return } diff --git a/lib/conn/conn.go b/lib/conn/conn.go index c003b1dd..38458d4b 100755 --- a/lib/conn/conn.go +++ b/lib/conn/conn.go @@ -210,21 +210,6 @@ func (s *Conn) SendHostInfo(h *file.Host) (int, error) { return s.Write(raw.Bytes()) } -//get task or host result of add -func (s *Conn) GetAddStatus() (b bool) { - binary.Read(s.Conn, binary.LittleEndian, &b) - return -} - -func (s *Conn) WriteAddOk() error { - return binary.Write(s.Conn, binary.LittleEndian, true) -} - -func (s *Conn) WriteAddFail() error { - defer s.Close() - return binary.Write(s.Conn, binary.LittleEndian, false) -} - //get task info func (s *Conn) GetHostInfo() (h *file.Host, err error) { var l int @@ -238,7 +223,7 @@ func (s *Conn) GetHostInfo() (h *file.Host, err error) { arr := strings.Split(string(buf[:l]), common.CONN_DATA_SEQ) h = new(file.Host) h.Target = new(file.Target) - h.Id = int(file.GetCsvDb().GetHostId()) + h.Id = int(file.GetDb().JsonDb.GetHostId()) h.Host = arr[0] h.Target.TargetStr = arr[1] h.HeaderChange = arr[2] @@ -328,7 +313,7 @@ func (s *Conn) GetTaskInfo() (t *file.Tunnel, err error) { t.Mode = arr[0] t.Ports = arr[1] t.Target.TargetStr = arr[2] - t.Id = int(file.GetCsvDb().GetTaskId()) + t.Id = int(file.GetDb().JsonDb.GetTaskId()) t.Status = true t.Flow = new(file.Flow) t.Remark = arr[3] @@ -379,6 +364,21 @@ func (s *Conn) WriteChan() (int, error) { return s.Write([]byte(common.WORK_CHAN)) } +//get task or host result of add +func (s *Conn) GetAddStatus() (b bool) { + binary.Read(s.Conn, binary.LittleEndian, &b) + return +} + +func (s *Conn) WriteAddOk() error { + return binary.Write(s.Conn, binary.LittleEndian, true) +} + +func (s *Conn) WriteAddFail() error { + defer s.Close() + return binary.Write(s.Conn, binary.LittleEndian, false) +} + //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/crypt/crypt.go b/lib/crypt/crypt.go index 17e99472..3f723ae7 100644 --- a/lib/crypt/crypt.go +++ b/lib/crypt/crypt.go @@ -19,11 +19,8 @@ func AesEncrypt(origData, key []byte) ([]byte, error) { } blockSize := block.BlockSize() origData = PKCS5Padding(origData, blockSize) - // origData = ZeroPadding(origData, block.BlockSize()) blockMode := cipher.NewCBCEncrypter(block, key[:blockSize]) crypted := make([]byte, len(origData)) - // 根据CryptBlocks方法的说明,如下方式初始化crypted也可以 - // crypted := origData blockMode.CryptBlocks(crypted, origData) return crypted, nil } @@ -52,7 +49,6 @@ func PKCS5Padding(ciphertext []byte, blockSize int) []byte { //Remove excess func PKCS5UnPadding(origData []byte) (error, []byte) { length := len(origData) - // 去掉最后一个字节 unpadding 次 unpadding := int(origData[length-1]) if (length - unpadding) < 0 { return errors.New("len error"), nil diff --git a/lib/file/csv.go b/lib/file/csv.go deleted file mode 100644 index 2d401d01..00000000 --- a/lib/file/csv.go +++ /dev/null @@ -1,35 +0,0 @@ -package file - -import ( - "github.com/cnlh/nps/lib/common" - "sort" - "sync" -) - -var ( - CsvDb *Csv - once sync.Once -) - -//init csv from file -func GetCsvDb() *Csv { - once.Do(func() { - CsvDb = NewCsv(common.GetRunPath()) - CsvDb.LoadClientFromCsv() - CsvDb.LoadTaskFromCsv() - CsvDb.LoadHostFromCsv() - }) - return CsvDb -} - -func GetMapKeys(m sync.Map, isSort bool, sortKey, order string) (keys []int) { - if sortKey != "" && isSort { - return sortClientByKey(m, sortKey, order) - } - m.Range(func(key, value interface{}) bool { - keys = append(keys, key.(int)) - return true - }) - sort.Ints(keys) - return -} diff --git a/lib/file/db.go b/lib/file/db.go new file mode 100644 index 00000000..7de111cd --- /dev/null +++ b/lib/file/db.go @@ -0,0 +1,356 @@ +package file + +import ( + "errors" + "fmt" + "github.com/cnlh/nps/lib/common" + "github.com/cnlh/nps/lib/crypt" + "github.com/cnlh/nps/lib/rate" + "net/http" + "regexp" + "sort" + "strings" + "sync" +) + +type DbUtils struct { + JsonDb *JsonDb +} + +var ( + Db *DbUtils + once sync.Once +) + +//init csv from file +func GetDb() *DbUtils { + once.Do(func() { + jsonDb := NewJsonDb(common.GetRunPath()) + jsonDb.LoadClientFromJsonFile() + jsonDb.LoadTaskFromJsonFile() + jsonDb.LoadHostFromJsonFile() + Db = &DbUtils{JsonDb: jsonDb} + }) + return Db +} + +func GetMapKeys(m sync.Map, isSort bool, sortKey, order string) (keys []int) { + if sortKey != "" && isSort { + return sortClientByKey(m, sortKey, order) + } + m.Range(func(key, value interface{}) bool { + keys = append(keys, key.(int)) + return true + }) + sort.Ints(keys) + return +} + +func (s *DbUtils) GetClientList(start, length int, search, sort, order string, clientId int) ([]*Client, int) { + list := make([]*Client, 0) + var cnt int + keys := GetMapKeys(s.JsonDb.Clients, true, sort, order) + for _, key := range keys { + if value, ok := s.JsonDb.Clients.Load(key); ok { + v := value.(*Client) + 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 + } + cnt++ + if start--; start < 0 { + if length--; length > 0 { + list = append(list, v) + } + } + } + } + return list, cnt +} + +func (s *DbUtils) GetIdByVerifyKey(vKey string, addr string) (id int, err error) { + var exist bool + s.JsonDb.Clients.Range(func(key, value interface{}) bool { + v := value.(*Client) + if common.Getverifyval(v.VerifyKey) == vKey && v.Status { + v.Addr = common.GetIpByAddr(addr) + id = v.Id + exist = true + return false + } + return true + }) + if exist { + return + } + return 0, errors.New("not found") +} + +func (s *DbUtils) NewTask(t *Tunnel) (err error) { + s.JsonDb.Tasks.Range(func(key, value interface{}) bool { + v := value.(*Tunnel) + if (v.Mode == "secret" || v.Mode == "p2p") && v.Password == t.Password { + err = errors.New(fmt.Sprintf("secret mode keys %s must be unique", t.Password)) + return false + } + return true + }) + if err != nil { + return + } + t.Flow = new(Flow) + s.JsonDb.Tasks.Store(t.Id, t) + s.JsonDb.StoreTasksToJsonFile() + return +} + +func (s *DbUtils) UpdateTask(t *Tunnel) error { + s.JsonDb.Tasks.Store(t.Id, t) + s.JsonDb.StoreTasksToJsonFile() + return nil +} + +func (s *DbUtils) DelTask(id int) error { + s.JsonDb.Tasks.Delete(id) + s.JsonDb.StoreTasksToJsonFile() + return nil +} + +//md5 password +func (s *DbUtils) GetTaskByMd5Password(p string) (t *Tunnel) { + s.JsonDb.Tasks.Range(func(key, value interface{}) bool { + if crypt.Md5(value.(*Tunnel).Password) == p { + t = value.(*Tunnel) + return false + } + return true + }) + return +} + +func (s *DbUtils) GetTask(id int) (t *Tunnel, err error) { + if v, ok := s.JsonDb.Tasks.Load(id); ok { + t = v.(*Tunnel) + return + } + err = errors.New("not found") + return +} + +func (s *DbUtils) DelHost(id int) error { + s.JsonDb.Hosts.Delete(id) + s.JsonDb.StoreHostToJsonFile() + return nil +} + +func (s *DbUtils) IsHostExist(h *Host) bool { + var exist bool + s.JsonDb.Hosts.Range(func(key, value interface{}) bool { + v := value.(*Host) + if v.Id != h.Id && v.Host == h.Host && h.Location == v.Location && (v.Scheme == "all" || v.Scheme == h.Scheme) { + exist = true + return false + } + return true + }) + return exist +} + +func (s *DbUtils) NewHost(t *Host) error { + if t.Location == "" { + t.Location = "/" + } + if s.IsHostExist(t) { + return errors.New("host has exist") + } + t.Flow = new(Flow) + s.JsonDb.Hosts.Store(t.Id, t) + s.JsonDb.StoreHostToJsonFile() + return nil +} + +func (s *DbUtils) GetHost(start, length int, id int, search string) ([]*Host, int) { + list := make([]*Host, 0) + var cnt int + keys := GetMapKeys(s.JsonDb.Hosts, false, "", "") + for _, key := range keys { + if value, ok := s.JsonDb.Hosts.Load(key); ok { + v := value.(*Host) + if search != "" && !(v.Id == common.GetIntNoErrByStr(search) || strings.Contains(v.Host, search) || strings.Contains(v.Remark, search)) { + continue + } + if id == 0 || v.Client.Id == id { + cnt++ + if start--; start < 0 { + if length--; length > 0 { + list = append(list, v) + } + } + } + } + } + return list, cnt +} + +func (s *DbUtils) DelClient(id int) error { + s.JsonDb.Clients.Delete(id) + s.JsonDb.StoreClientsToJsonFile() + return nil +} + +func (s *DbUtils) NewClient(c *Client) error { + var isNotSet bool + if c.WebUserName != "" && !s.VerifyUserName(c.WebUserName, c.Id) { + return errors.New("web login username duplicate, please reset") + } +reset: + if c.VerifyKey == "" || isNotSet { + isNotSet = true + c.VerifyKey = crypt.GetRandomString(16) + } + if c.RateLimit == 0 { + c.Rate = rate.NewRate(int64(2 << 23)) + c.Rate.Start() + } + if !s.VerifyVkey(c.VerifyKey, c.Id) { + if isNotSet { + goto reset + } + return errors.New("Vkey duplicate, please reset") + } + if c.Id == 0 { + c.Id = int(s.JsonDb.GetClientId()) + } + if c.Flow == nil { + c.Flow = new(Flow) + } + s.JsonDb.Clients.Store(c.Id, c) + s.JsonDb.StoreClientsToJsonFile() + return nil +} + +func (s *DbUtils) VerifyVkey(vkey string, id int) (res bool) { + res = true + s.JsonDb.Clients.Range(func(key, value interface{}) bool { + v := value.(*Client) + if v.VerifyKey == vkey && v.Id != id { + res = false + return false + } + return true + }) + return res +} + +func (s *DbUtils) VerifyUserName(username string, id int) (res bool) { + res = true + s.JsonDb.Clients.Range(func(key, value interface{}) bool { + v := value.(*Client) + if v.WebUserName == username && v.Id != id { + res = false + return false + } + return true + }) + return res +} + +func (s *DbUtils) UpdateClient(t *Client) error { + s.JsonDb.Clients.Store(t.Id, t) + if t.RateLimit == 0 { + t.Rate = rate.NewRate(int64(2 << 23)) + t.Rate.Start() + } + return nil +} + +func (s *DbUtils) IsPubClient(id int) bool { + client, err := s.GetClient(id) + if err == nil { + return client.NoDisplay + } + return false +} + +func (s *DbUtils) GetClient(id int) (c *Client, err error) { + if v, ok := s.JsonDb.Clients.Load(id); ok { + c = v.(*Client) + return + } + err = errors.New("未找到客户端") + return +} + +func (s *DbUtils) GetClientIdByVkey(vkey string) (id int, err error) { + var exist bool + s.JsonDb.Clients.Range(func(key, value interface{}) bool { + v := value.(*Client) + if crypt.Md5(v.VerifyKey) == vkey { + exist = true + id = v.Id + return false + } + return true + }) + if exist { + return + } + err = errors.New("未找到客户端") + return +} + +func (s *DbUtils) GetHostById(id int) (h *Host, err error) { + if v, ok := s.JsonDb.Hosts.Load(id); ok { + h = v.(*Host) + return + } + err = errors.New("The host could not be parsed") + return +} + +//get key by host from x +func (s *DbUtils) GetInfoByHost(host string, r *http.Request) (h *Host, err error) { + var hosts []*Host + //Handling Ported Access + host = common.GetIpByAddr(host) + s.JsonDb.Hosts.Range(func(key, value interface{}) bool { + v := value.(*Host) + if v.IsClose { + return true + } + //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 true + } + if len(re.FindAllString(host, -1)) > 0 && (v.Scheme == "all" || v.Scheme == r.URL.Scheme) { + //URL routing + hosts = append(hosts, v) + } + return true + }) + + 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 { + return + } + err = errors.New("The host could not be parsed") + return +} diff --git a/lib/file/file.go b/lib/file/file.go index cd47db40..541e6178 100644 --- a/lib/file/file.go +++ b/lib/file/file.go @@ -3,21 +3,17 @@ package file import ( "encoding/json" "errors" - "fmt" "github.com/cnlh/nps/lib/common" - "github.com/cnlh/nps/lib/crypt" "github.com/cnlh/nps/lib/rate" - "net/http" "os" "path/filepath" - "regexp" "strings" "sync" "sync/atomic" ) -func NewCsv(runPath string) *Csv { - return &Csv{ +func NewJsonDb(runPath string) *JsonDb { + return &JsonDb{ RunPath: runPath, TaskFilePath: filepath.Join(runPath, "conf", "tasks.json"), HostFilePath: filepath.Join(runPath, "conf", "hosts.json"), @@ -25,21 +21,21 @@ func NewCsv(runPath string) *Csv { } } -type Csv struct { +type JsonDb struct { Tasks sync.Map - Hosts sync.Map //域名列表 + Hosts sync.Map HostsTmp sync.Map - Clients sync.Map //客户端 - RunPath string //存储根目录 - ClientIncreaseId int32 //客户端id - TaskIncreaseId int32 //任务自增ID - HostIncreaseId int32 //host increased id - TaskFilePath string - HostFilePath string - ClientFilePath string + Clients sync.Map + RunPath string + ClientIncreaseId int32 //client increased id + TaskIncreaseId int32 //task increased id + HostIncreaseId int32 //host increased id + TaskFilePath string //task file path + HostFilePath string //host file path + ClientFilePath string //client file path } -func (s *Csv) LoadTaskFromCsv() { +func (s *JsonDb) LoadTaskFromJsonFile() { loadSyncMapFromFile(s.TaskFilePath, func(v string) { var err error post := new(Tunnel) @@ -56,7 +52,7 @@ func (s *Csv) LoadTaskFromCsv() { }) } -func (s *Csv) LoadClientFromCsv() { +func (s *JsonDb) LoadClientFromJsonFile() { loadSyncMapFromFile(s.ClientFilePath, func(v string) { post := new(Client) if json.Unmarshal([]byte(v), &post) != nil { @@ -68,6 +64,7 @@ func (s *Csv) LoadClientFromCsv() { post.Rate = rate.NewRate(int64(2 << 23)) } post.Rate.Start() + post.NowConn = 0 s.Clients.Store(post.Id, post) if post.Id > int(s.ClientIncreaseId) { s.ClientIncreaseId = int32(post.Id) @@ -75,7 +72,7 @@ func (s *Csv) LoadClientFromCsv() { }) } -func (s *Csv) LoadHostFromCsv() { +func (s *JsonDb) LoadHostFromJsonFile() { loadSyncMapFromFile(s.HostFilePath, func(v string) { var err error post := new(Host) @@ -92,259 +89,7 @@ func (s *Csv) LoadHostFromCsv() { }) } -func (s *Csv) GetIdByVerifyKey(vKey string, addr string) (id int, err error) { - var exist bool - s.Clients.Range(func(key, value interface{}) bool { - v := value.(*Client) - if common.Getverifyval(v.VerifyKey) == vKey && v.Status { - v.Addr = common.GetIpByAddr(addr) - id = v.Id - exist = true - return false - } - return true - }) - if exist { - return - } - return 0, errors.New("not found") -} - -func (s *Csv) NewTask(t *Tunnel) (err error) { - s.Tasks.Range(func(key, value interface{}) bool { - v := value.(*Tunnel) - if (v.Mode == "secret" || v.Mode == "p2p") && v.Password == t.Password { - err = errors.New(fmt.Sprintf("Secret mode keys %s must be unique", t.Password)) - return false - } - return true - }) - if err != nil { - return - } - t.Flow = new(Flow) - s.Tasks.Store(t.Id, t) - s.StoreTasksToCsv() - return -} - -func (s *Csv) UpdateTask(t *Tunnel) error { - s.Tasks.Store(t.Id, t) - s.StoreTasksToCsv() - return nil -} - -func (s *Csv) DelTask(id int) error { - s.Tasks.Delete(id) - s.StoreTasksToCsv() - return nil -} - -//md5 password -func (s *Csv) GetTaskByMd5Password(p string) (t *Tunnel) { - s.Tasks.Range(func(key, value interface{}) bool { - if crypt.Md5(value.(*Tunnel).Password) == p { - t = value.(*Tunnel) - return false - } - return true - }) - return -} - -func (s *Csv) GetTask(id int) (t *Tunnel, err error) { - if v, ok := s.Tasks.Load(id); ok { - t = v.(*Tunnel) - return - } - err = errors.New("not found") - return -} - -func (s *Csv) StoreHostToCsv() { - storeSyncMapToFile(s.Hosts, s.HostFilePath) -} - -func (s *Csv) StoreTasksToCsv() { - storeSyncMapToFile(s.Tasks, s.TaskFilePath) -} - -func (s *Csv) StoreClientsToCsv() { - storeSyncMapToFile(s.Clients, s.ClientFilePath) -} - -func (s *Csv) DelHost(id int) error { - s.Hosts.Delete(id) - s.StoreHostToCsv() - return nil -} - -func (s *Csv) GetMapLen(m sync.Map) int { - var c int - m.Range(func(key, value interface{}) bool { - c++ - return true - }) - return c -} - -func (s *Csv) IsHostExist(h *Host) bool { - var exist bool - s.Hosts.Range(func(key, value interface{}) bool { - v := value.(*Host) - if v.Host == h.Host && h.Location == v.Location && (v.Scheme == "all" || v.Scheme == h.Scheme) { - exist = true - return false - } - return true - }) - return exist -} - -func (s *Csv) NewHost(t *Host) error { - if t.Location == "" { - t.Location = "/" - } - if s.IsHostExist(t) { - return errors.New("host has exist") - } - t.Flow = new(Flow) - s.Hosts.Store(t.Id, t) - s.StoreHostToCsv() - return nil -} - -func (s *Csv) GetHost(start, length int, id int, search string) ([]*Host, int) { - list := make([]*Host, 0) - var cnt int - keys := GetMapKeys(s.Hosts, false, "", "") - for _, key := range keys { - if value, ok := s.Hosts.Load(key); ok { - v := value.(*Host) - if search != "" && !(v.Id == common.GetIntNoErrByStr(search) || strings.Contains(v.Host, search) || strings.Contains(v.Remark, search)) { - continue - } - if id == 0 || v.Client.Id == id { - cnt++ - if start--; start < 0 { - if length--; length > 0 { - list = append(list, v) - } - } - } - } - } - return list, cnt -} - -func (s *Csv) DelClient(id int) error { - s.Clients.Delete(id) - s.StoreClientsToCsv() - return nil -} - -func (s *Csv) NewClient(c *Client) error { - var isNotSet bool - if c.WebUserName != "" && !s.VerifyUserName(c.WebUserName, c.Id) { - return errors.New("web login username duplicate, please reset") - } -reset: - if c.VerifyKey == "" || isNotSet { - isNotSet = true - c.VerifyKey = crypt.GetRandomString(16) - } - if c.RateLimit == 0 { - c.Rate = rate.NewRate(int64(2 << 23)) - c.Rate.Start() - } - if !s.VerifyVkey(c.VerifyKey, c.Id) { - if isNotSet { - goto reset - } - return errors.New("Vkey duplicate, please reset") - } - if c.Id == 0 { - c.Id = int(s.GetClientId()) - } - if c.Flow == nil { - c.Flow = new(Flow) - } - s.Clients.Store(c.Id, c) - s.StoreClientsToCsv() - return nil -} - -func (s *Csv) VerifyVkey(vkey string, id int) (res bool) { - res = true - s.Clients.Range(func(key, value interface{}) bool { - v := value.(*Client) - if v.VerifyKey == vkey && v.Id != id { - res = false - return false - } - return true - }) - return res -} - -func (s *Csv) VerifyUserName(username string, id int) (res bool) { - res = true - s.Clients.Range(func(key, value interface{}) bool { - v := value.(*Client) - if v.WebUserName == username && v.Id != id { - res = false - return false - } - return true - }) - return res -} - -func (s *Csv) UpdateClient(t *Client) error { - s.Clients.Store(t.Id, t) - if t.RateLimit == 0 { - t.Rate = rate.NewRate(int64(2 << 23)) - t.Rate.Start() - } - return nil -} - -func (s *Csv) GetClientList(start, length int, search, sort, order string, clientId int) ([]*Client, int) { - list := make([]*Client, 0) - var cnt int - keys := GetMapKeys(s.Clients, true, sort, order) - for _, key := range keys { - if value, ok := s.Clients.Load(key); ok { - v := value.(*Client) - 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 - } - cnt++ - if start--; start < 0 { - if length--; length > 0 { - list = append(list, v) - } - } - } - } - return list, cnt -} - -func (s *Csv) IsPubClient(id int) bool { - client, err := s.GetClient(id) - if err == nil { - return client.NoDisplay - } - return false -} - -func (s *Csv) GetClient(id int) (c *Client, err error) { +func (s *JsonDb) GetClient(id int) (c *Client, err error) { if v, ok := s.Clients.Load(id); ok { c = v.(*Client) return @@ -353,84 +98,27 @@ func (s *Csv) GetClient(id int) (c *Client, err error) { return } -func (s *Csv) GetClientIdByVkey(vkey string) (id int, err error) { - var exist bool - s.Clients.Range(func(key, value interface{}) bool { - v := value.(*Client) - if crypt.Md5(v.VerifyKey) == vkey { - exist = true - id = v.Id - return false - } - return true - }) - if exist { - return - } - err = errors.New("未找到客户端") - return +func (s *JsonDb) StoreHostToJsonFile() { + storeSyncMapToFile(s.Hosts, s.HostFilePath) } -func (s *Csv) GetHostById(id int) (h *Host, err error) { - if v, ok := s.Hosts.Load(id); ok { - h = v.(*Host) - return - } - err = errors.New("The host could not be parsed") - return +func (s *JsonDb) StoreTasksToJsonFile() { + storeSyncMapToFile(s.Tasks, s.TaskFilePath) } -//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) - s.Hosts.Range(func(key, value interface{}) bool { - v := value.(*Host) - if v.IsClose { - return true - } - //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 true - } - if len(re.FindAllString(host, -1)) > 0 && (v.Scheme == "all" || v.Scheme == r.URL.Scheme) { - //URL routing - hosts = append(hosts, v) - } - return true - }) - - 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 { - return - } - err = errors.New("The host could not be parsed") - return +func (s *JsonDb) StoreClientsToJsonFile() { + storeSyncMapToFile(s.Clients, s.ClientFilePath) } -func (s *Csv) GetClientId() int32 { +func (s *JsonDb) GetClientId() int32 { return atomic.AddInt32(&s.ClientIncreaseId, 1) } -func (s *Csv) GetTaskId() int32 { +func (s *JsonDb) GetTaskId() int32 { return atomic.AddInt32(&s.TaskIncreaseId, 1) } -func (s *Csv) GetHostId() int32 { +func (s *JsonDb) GetHostId() int32 { return atomic.AddInt32(&s.HostIncreaseId, 1) } diff --git a/lib/file/obj.go b/lib/file/obj.go index 80f6b9be..6a21a40a 100644 --- a/lib/file/obj.go +++ b/lib/file/obj.go @@ -23,6 +23,13 @@ func (s *Flow) Add(in, out int64) { s.ExportFlow += int64(out) } +type Config struct { + U string + P string + Compress bool + Crypt bool +} + type Client struct { Cnf *Config Id int //id @@ -79,7 +86,7 @@ func (s *Client) GetConn() bool { } func (s *Client) HasTunnel(t *Tunnel) (exist bool) { - GetCsvDb().Tasks.Range(func(key, value interface{}) bool { + GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool { v := value.(*Tunnel) if v.Client.Id == s.Id && v.Port == t.Port { exist = true @@ -92,7 +99,7 @@ func (s *Client) HasTunnel(t *Tunnel) (exist bool) { func (s *Client) HasHost(h *Host) bool { var has bool - GetCsvDb().Hosts.Range(func(key, value interface{}) bool { + GetDb().JsonDb.Hosts.Range(func(key, value interface{}) bool { v := value.(*Host) if v.Client.Id == s.Id && v.Host == h.Host && h.Location == v.Location { has = true @@ -104,17 +111,17 @@ func (s *Client) HasHost(h *Host) bool { } type Tunnel struct { - Id int //Id - Port int //服务端监听端口 + Id int + Port int ServerIp string - Mode string //启动方式 - Status bool //设置是否开启 - RunStatus bool //当前运行状态 - Client *Client //所属客户端id - Ports string //客户端与服务端传递 + Mode string + Status bool + RunStatus bool + Client *Client + Ports string Flow *Flow - Password string //私密模式密码,唯一 - Remark string //备注 + Password string + Remark string TargetAddr string NoStore bool LocalPath string @@ -137,10 +144,27 @@ type Health struct { sync.RWMutex } +type Host struct { + Id int + Host string //host + HeaderChange string //header change + HostChange string //host change + Location string //url router + Remark string //remark + Scheme string //http https all + NoStore bool + IsClose bool + Flow *Flow + Client *Client + Target *Target //目标 + Health `json:"-"` + sync.RWMutex +} + type Target struct { nowIndex int TargetStr string - TargetArr []string //目标 + TargetArr []string sync.RWMutex } @@ -162,27 +186,3 @@ func (s *Target) GetRandomTarget() (string, error) { s.nowIndex++ return s.TargetArr[s.nowIndex], nil } - -type Config struct { - U string - P string - Compress bool - Crypt bool -} - -type Host struct { - Id int - Host string //host - HeaderChange string //header change - HostChange string //host change - Location string //url router - Remark string //remark - Scheme string //http https all - NoStore bool - IsClose bool - Flow *Flow - Client *Client - Target *Target //目标 - Health `json:"-"` - sync.RWMutex -} diff --git a/server/proxy/http.go b/server/proxy/http.go index 4d090634..c2d5d194 100644 --- a/server/proxy/http.go +++ b/server/proxy/http.go @@ -58,7 +58,7 @@ func (s *httpServer) processHttps(c net.Conn) { return } var host *file.Host - file.GetCsvDb().Hosts.Range(func(key, value interface{}) bool { + file.GetDb().JsonDb.Hosts.Range(func(key, value interface{}) bool { v := value.(*file.Host) if v.Scheme != "https" && v.Scheme != "all" { return true @@ -193,7 +193,7 @@ func (s *httpServer) process(c *conn.Conn, r *http.Request) { targetAddr string wg sync.WaitGroup ) - if host, err = file.GetCsvDb().GetInfoByHost(r.Host, r); err != nil { + if host, err = file.GetDb().GetInfoByHost(r.Host, r); err != nil { logs.Notice("the url %s %s %s can't be parsed!", r.URL.Scheme, r.Host, r.RequestURI) goto end } @@ -245,7 +245,7 @@ func (s *httpServer) process(c *conn.Conn, r *http.Request) { r.Method = "POST" } logs.Trace("new %s connection,clientId %d,host %s,url %s,remote address %s", r.URL.Scheme, host.Client.Id, r.Host, r.URL, r.RemoteAddr) - if hostTmp, err := file.GetCsvDb().GetInfoByHost(r.Host, r); err != nil { + if hostTmp, err := file.GetDb().GetInfoByHost(r.Host, r); err != nil { logs.Notice("the url %s %s %s can't be parsed!", r.URL.Scheme, r.Host, r.RequestURI) break } else if host != lastHost { diff --git a/server/server.go b/server/server.go index 51fff299..87662afd 100644 --- a/server/server.go +++ b/server/server.go @@ -21,27 +21,24 @@ import ( ) var ( - Bridge *bridge.Bridge - RunList map[int]interface{} //运行中的任务 - serverStatus []map[string]interface{} + Bridge *bridge.Bridge + RunList map[int]interface{} ) func init() { RunList = make(map[int]interface{}) - serverStatus = make([]map[string]interface{}, 0, 1500) - go getSeverStatus() } -//从csv文件中恢复任务 +//init task from db func InitFromCsv() { //Add a public password if vkey := beego.AppConfig.String("public_vkey"); vkey != "" { c := file.NewClient(vkey, true, true) - file.GetCsvDb().NewClient(c) + file.GetDb().NewClient(c) RunList[c.Id] = nil } //Initialize services in server-side files - file.GetCsvDb().Tasks.Range(func(key, value interface{}) bool { + file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool { if value.(*file.Tunnel).Status { AddTask(value.(*file.Tunnel)) } @@ -49,6 +46,7 @@ func InitFromCsv() { }) } +//get bridge command func DealBridgeTask() { for { select { @@ -58,16 +56,16 @@ func DealBridgeTask() { StopServer(t.Id) case id := <-Bridge.CloseClient: DelTunnelAndHostByClientId(id, true) - if v, ok := file.GetCsvDb().Clients.Load(id); ok { + if v, ok := file.GetDb().JsonDb.Clients.Load(id); ok { if v.(*file.Client).NoStore { - file.GetCsvDb().DelClient(id) + file.GetDb().DelClient(id) } } case tunnel := <-Bridge.OpenTask: StartTask(tunnel.Id) case s := <-Bridge.SecretChan: logs.Trace("New secret connection, addr", s.Conn.Conn.RemoteAddr()) - if t := file.GetCsvDb().GetTaskByMd5Password(s.Password); t != nil { + if t := file.GetDb().GetTaskByMd5Password(s.Password); t != nil { if !t.Client.GetConn() { logs.Info("Connections exceed the current client %d limit", t.Client.Id) s.Conn.Close() @@ -158,11 +156,11 @@ func StopServer(id int) error { } else { logs.Warn("stop server id %d error", id) } - if t, err := file.GetCsvDb().GetTask(id); err != nil { + if t, err := file.GetDb().GetTask(id); err != nil { return err } else { t.Status = false - file.GetCsvDb().UpdateTask(t) + file.GetDb().UpdateTask(t) } delete(RunList, id) return nil @@ -202,12 +200,12 @@ func AddTask(t *file.Tunnel) error { //start task func StartTask(id int) error { - if t, err := file.GetCsvDb().GetTask(id); err != nil { + if t, err := file.GetDb().GetTask(id); err != nil { return err } else { AddTask(t) t.Status = true - file.GetCsvDb().UpdateTask(t) + file.GetDb().UpdateTask(t) } return nil } @@ -219,16 +217,16 @@ func DelTask(id int) error { return err } } - return file.GetCsvDb().DelTask(id) + return file.GetDb().DelTask(id) } //get task list by page num func GetTunnel(start, length int, typeVal string, clientId int, search string) ([]*file.Tunnel, int) { list := make([]*file.Tunnel, 0) var cnt int - keys := file.GetMapKeys(file.GetCsvDb().Tasks, false, "", "") + keys := file.GetMapKeys(file.GetDb().JsonDb.Tasks, false, "", "") for _, key := range keys { - if value, ok := file.GetCsvDb().Tasks.Load(key); ok { + if value, ok := file.GetDb().JsonDb.Tasks.Load(key); ok { v := value.(*file.Tunnel) if (typeVal != "" && v.Mode != typeVal || (clientId != 0 && v.Client.Id != clientId)) || (typeVal == "" && clientId != v.Client.Id) { continue @@ -257,15 +255,15 @@ func GetTunnel(start, length int, typeVal string, clientId int, search string) ( return list, cnt } -//获取客户端列表 +//get client list func GetClientList(start, length int, search, sort, order string, clientId int) (list []*file.Client, cnt int) { - list, cnt = file.GetCsvDb().GetClientList(start, length, search, sort, order, clientId) + list, cnt = file.GetDb().GetClientList(start, length, search, sort, order, clientId) dealClientData() return } func dealClientData() { - file.GetCsvDb().Clients.Range(func(key, value interface{}) bool { + file.GetDb().JsonDb.Clients.Range(func(key, value interface{}) bool { v := value.(*file.Client) if _, ok := Bridge.Client.Load(v.Id); ok { v.IsConnect = true @@ -274,7 +272,7 @@ func dealClientData() { } v.Flow.InletFlow = 0 v.Flow.ExportFlow = 0 - file.GetCsvDb().Hosts.Range(func(key, value interface{}) bool { + file.GetDb().JsonDb.Hosts.Range(func(key, value interface{}) bool { h := value.(*file.Host) if h.Client.Id == v.Id { v.Flow.InletFlow += h.Flow.InletFlow @@ -282,7 +280,7 @@ func dealClientData() { } return true }) - file.GetCsvDb().Tasks.Range(func(key, value interface{}) bool { + file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool { t := value.(*file.Tunnel) if t.Client.Id == v.Id { v.Flow.InletFlow += t.Flow.InletFlow @@ -295,10 +293,10 @@ func dealClientData() { return } -//根据客户端id删除其所属的所有隧道和域名 +//delete all host and tasks by client id func DelTunnelAndHostByClientId(clientId int, justDelNoStore bool) { var ids []int - file.GetCsvDb().Tasks.Range(func(key, value interface{}) bool { + file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool { v := value.(*file.Tunnel) if justDelNoStore && !v.NoStore { return true @@ -312,7 +310,7 @@ func DelTunnelAndHostByClientId(clientId int, justDelNoStore bool) { DelTask(id) } ids = ids[:0] - file.GetCsvDb().Hosts.Range(func(key, value interface{}) bool { + file.GetDb().JsonDb.Hosts.Range(func(key, value interface{}) bool { v := value.(*file.Host) if justDelNoStore && !v.NoStore { return true @@ -323,23 +321,23 @@ func DelTunnelAndHostByClientId(clientId int, justDelNoStore bool) { return true }) for _, id := range ids { - file.GetCsvDb().DelHost(id) + file.GetDb().DelHost(id) } } -//关闭客户端连接 +//close the client func DelClientConnect(clientId int) { Bridge.DelClient(clientId) } func GetDashboardData() map[string]interface{} { data := make(map[string]interface{}) - data["hostCount"] = file.GetCsvDb().GetMapLen(file.GetCsvDb().Hosts) - data["clientCount"] = file.GetCsvDb().GetMapLen(file.GetCsvDb().Clients) - 1 //Remove the public key client + data["hostCount"] = common.GeSynctMapLen(file.GetDb().JsonDb.Hosts) + data["clientCount"] = common.GeSynctMapLen(file.GetDb().JsonDb.Clients) - 1 //Remove the public key client dealClientData() c := 0 var in, out int64 - file.GetCsvDb().Clients.Range(func(key, value interface{}) bool { + file.GetDb().JsonDb.Clients.Range(func(key, value interface{}) bool { v := value.(*file.Client) if v.IsConnect { c += 1 @@ -352,7 +350,7 @@ func GetDashboardData() map[string]interface{} { data["inletFlowCount"] = int(in) data["exportFlowCount"] = int(out) var tcp, udp, secret, socks5, p2p, http int - file.GetCsvDb().Tasks.Range(func(key, value interface{}) bool { + file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool { switch value.(*file.Tunnel).Mode { case "tcp": tcp += 1 @@ -386,7 +384,7 @@ func GetDashboardData() map[string]interface{} { data["logLevel"] = beego.AppConfig.String("log_level") tcpCount := 0 - file.GetCsvDb().Clients.Range(func(key, value interface{}) bool { + file.GetDb().JsonDb.Clients.Range(func(key, value interface{}) bool { tcpCount += int(value.(*file.Client).NowConn) return true }) @@ -416,10 +414,10 @@ func GetDashboardData() map[string]interface{} { } //chart var fg int - if len(serverStatus) >= 10 { - fg = len(serverStatus) / 10 + if len(tool.ServerStatus) >= 10 { + fg = len(tool.ServerStatus) / 10 for i := 0; i <= 9; i++ { - data["sys"+strconv.Itoa(i+1)] = serverStatus[i*fg] + data["sys"+strconv.Itoa(i+1)] = tool.ServerStatus[i*fg] } } return data @@ -430,51 +428,9 @@ func flowSession(m time.Duration) { for { select { case <-ticker.C: - file.GetCsvDb().StoreHostToCsv() - file.GetCsvDb().StoreTasksToCsv() + file.GetDb().JsonDb.StoreHostToJsonFile() + file.GetDb().JsonDb.StoreTasksToJsonFile() + file.GetDb().JsonDb.StoreClientsToJsonFile() } } } - -func getSeverStatus() { - for { - if len(serverStatus) < 10 { - time.Sleep(time.Second) - } else { - time.Sleep(time.Minute) - } - cpuPercet, _ := cpu.Percent(0, true) - var cpuAll float64 - for _, v := range cpuPercet { - cpuAll += v - } - m := make(map[string]interface{}) - loads, _ := load.Avg() - m["load1"] = loads.Load1 - m["load5"] = loads.Load5 - m["load15"] = loads.Load15 - m["cpu"] = math.Round(cpuAll / float64(len(cpuPercet))) - swap, _ := mem.SwapMemory() - m["swap_mem"] = math.Round(swap.UsedPercent) - vir, _ := mem.VirtualMemory() - m["virtual_mem"] = math.Round(vir.UsedPercent) - conn, _ := net.ProtoCounters(nil) - io1, _ := net.IOCounters(false) - time.Sleep(time.Millisecond * 500) - io2, _ := net.IOCounters(false) - if len(io2) > 0 && len(io1) > 0 { - m["io_send"] = (io2[0].BytesSent - io1[0].BytesSent) * 2 - m["io_recv"] = (io2[0].BytesRecv - io1[0].BytesRecv) * 2 - } - t := time.Now() - m["time"] = strconv.Itoa(t.Hour()) + ":" + strconv.Itoa(t.Minute()) + ":" + strconv.Itoa(t.Second()) - - for _, v := range conn { - m[v.Protocol] = v.Stats["CurrEstab"] - } - if len(serverStatus) >= 1440 { - serverStatus = serverStatus[1:] - } - serverStatus = append(serverStatus, m) - } -} diff --git a/server/test/test.go b/server/test/test.go index 47243d74..4b52d575 100644 --- a/server/test/test.go +++ b/server/test/test.go @@ -12,7 +12,7 @@ import ( func TestServerConfig() { var postTcpArr []int var postUdpArr []int - file.GetCsvDb().Tasks.Range(func(key, value interface{}) bool { + file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool { v := value.(*file.Tunnel) if v.Mode == "udp" { isInArr(&postUdpArr, v.Port, v.Remark, "udp") diff --git a/server/tool/utils.go b/server/tool/utils.go index 578c5b73..6b733625 100644 --- a/server/tool/utils.go +++ b/server/tool/utils.go @@ -3,9 +3,24 @@ package tool import ( "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/vender/github.com/astaxie/beego" + "github.com/shirou/gopsutil/cpu" + "github.com/shirou/gopsutil/load" + "github.com/shirou/gopsutil/mem" + "github.com/shirou/gopsutil/net" + "math" + "strconv" + "time" ) -var ports []int +var ( + ports []int + ServerStatus []map[string]interface{} +) + +func init() { + ServerStatus = make([]map[string]interface{}, 0, 1500) + go getSeverStatus() +} func InitAllowPort() { p := beego.AppConfig.String("allow_ports") @@ -28,3 +43,48 @@ func TestServerPort(p int, m string) (b bool) { } return } + +func getSeverStatus() { + for { + if len(ServerStatus) < 10 { + time.Sleep(time.Second) + } else { + time.Sleep(time.Minute) + } + cpuPercet, _ := cpu.Percent(0, true) + var cpuAll float64 + for _, v := range cpuPercet { + cpuAll += v + } + m := make(map[string]interface{}) + loads, _ := load.Avg() + m["load1"] = loads.Load1 + m["load5"] = loads.Load5 + m["load15"] = loads.Load15 + m["cpu"] = math.Round(cpuAll / float64(len(cpuPercet))) + swap, _ := mem.SwapMemory() + m["swap_mem"] = math.Round(swap.UsedPercent) + vir, _ := mem.VirtualMemory() + m["virtual_mem"] = math.Round(vir.UsedPercent) + conn, _ := net.ProtoCounters(nil) + io1, _ := net.IOCounters(false) + time.Sleep(time.Millisecond * 500) + io2, _ := net.IOCounters(false) + if len(io2) > 0 && len(io1) > 0 { + m["io_send"] = (io2[0].BytesSent - io1[0].BytesSent) * 2 + m["io_recv"] = (io2[0].BytesRecv - io1[0].BytesRecv) * 2 + } + t := time.Now() + m["time"] = strconv.Itoa(t.Hour()) + ":" + strconv.Itoa(t.Minute()) + ":" + strconv.Itoa(t.Second()) + + for _, v := range conn { + m[v.Protocol] = v.Stats["CurrEstab"] + } + if len(ServerStatus) >= 1440 { + ServerStatus = ServerStatus[1:] + } + ServerStatus = append(ServerStatus, m) + } +} + + diff --git a/web/controllers/base.go b/web/controllers/base.go index 631efbcd..907b359c 100755 --- a/web/controllers/base.go +++ b/web/controllers/base.go @@ -156,13 +156,13 @@ func (s *BaseController) CheckUserAuth() { if id := s.GetIntNoErr("id"); id != 0 { belong := false if strings.Contains(s.actionName, "h") { - if v, ok := file.GetCsvDb().Hosts.Load(id); ok { + if v, ok := file.GetDb().JsonDb.Hosts.Load(id); ok { if v.(*file.Host).Client.Id == s.GetSession("clientId").(int) { belong = true } } } else { - if v, ok := file.GetCsvDb().Tasks.Load(id); ok { + if v, ok := file.GetDb().JsonDb.Tasks.Load(id); ok { if v.(*file.Tunnel).Client.Id == s.GetSession("clientId").(int) { belong = true } diff --git a/web/controllers/client.go b/web/controllers/client.go index 4d039c5a..de8e551a 100644 --- a/web/controllers/client.go +++ b/web/controllers/client.go @@ -40,7 +40,7 @@ func (s *ClientController) Add() { } else { t := &file.Client{ VerifyKey: s.GetString("vkey"), - Id: int(file.GetCsvDb().GetClientId()), + Id: int(file.GetDb().JsonDb.GetClientId()), Status: true, Remark: s.GetString("remark"), Cnf: &file.Config{ @@ -64,7 +64,7 @@ func (s *ClientController) Add() { t.Rate = rate.NewRate(int64(t.RateLimit * 1024)) t.Rate.Start() } - if err := file.GetCsvDb().NewClient(t); err != nil { + if err := file.GetDb().NewClient(t); err != nil { s.AjaxErr(err.Error()) } s.AjaxOk("add success") @@ -74,7 +74,7 @@ func (s *ClientController) GetClient() { if s.Ctx.Request.Method == "POST" { id := s.GetIntNoErr("id") data := make(map[string]interface{}) - if c, err := file.GetCsvDb().GetClient(id); err != nil { + if c, err := file.GetDb().GetClient(id); err != nil { data["code"] = 0 } else { data["code"] = 1 @@ -90,7 +90,7 @@ func (s *ClientController) Edit() { id := s.GetIntNoErr("id") if s.Ctx.Request.Method == "GET" { s.Data["menu"] = "client" - if c, err := file.GetCsvDb().GetClient(id); err != nil { + if c, err := file.GetDb().GetClient(id); err != nil { s.error() } else { s.Data["c"] = c @@ -98,17 +98,17 @@ func (s *ClientController) Edit() { s.SetInfo("edit client") s.display() } else { - if c, err := file.GetCsvDb().GetClient(id); err != nil { + if c, err := file.GetDb().GetClient(id); err != nil { s.error() } else { if s.GetString("web_username") != "" { - if s.GetString("web_username") == beego.AppConfig.String("web_username") || !file.GetCsvDb().VerifyUserName(s.GetString("web_username"), c.Id) { + if s.GetString("web_username") == beego.AppConfig.String("web_username") || !file.GetDb().VerifyUserName(s.GetString("web_username"), c.Id) { s.AjaxErr("web login username duplicate, please reset") return } } if s.GetSession("isAdmin").(bool) { - if !file.GetCsvDb().VerifyVkey(s.GetString("vkey"), c.Id) { + if !file.GetDb().VerifyVkey(s.GetString("vkey"), c.Id) { s.AjaxErr("Vkey duplicate, please reset") return } @@ -135,7 +135,7 @@ func (s *ClientController) Edit() { c.Rate = rate.NewRate(int64(2 << 23)) c.Rate.Start() } - file.GetCsvDb().StoreClientsToCsv() + file.GetDb().JsonDb.StoreClientsToJsonFile() } s.AjaxOk("save success") } @@ -144,7 +144,7 @@ func (s *ClientController) Edit() { //更改状态 func (s *ClientController) ChangeStatus() { id := s.GetIntNoErr("id") - if client, err := file.GetCsvDb().GetClient(id); err == nil { + if client, err := file.GetDb().GetClient(id); err == nil { client.Status = s.GetBoolNoErr("status") if client.Status == false { server.DelClientConnect(client.Id) @@ -157,7 +157,7 @@ func (s *ClientController) ChangeStatus() { //删除客户端 func (s *ClientController) Del() { id := s.GetIntNoErr("id") - if err := file.GetCsvDb().DelClient(id); err != nil { + if err := file.GetDb().DelClient(id); err != nil { s.AjaxErr("delete error") } server.DelTunnelAndHostByClientId(id, false) diff --git a/web/controllers/index.go b/web/controllers/index.go index e09f796e..7a244436 100755 --- a/web/controllers/index.go +++ b/web/controllers/index.go @@ -94,7 +94,7 @@ func (s *IndexController) Add() { ServerIp: s.GetString("server_ip"), Mode: s.GetString("type"), Target: &file.Target{TargetStr: s.GetString("target")}, - Id: int(file.GetCsvDb().GetTaskId()), + Id: int(file.GetDb().JsonDb.GetTaskId()), Status: true, Remark: s.GetString("remark"), Password: s.GetString("password"), @@ -106,10 +106,10 @@ func (s *IndexController) Add() { s.AjaxErr("The port cannot be opened because it may has been occupied or is no longer allowed.") } var err error - if t.Client, err = file.GetCsvDb().GetClient(s.GetIntNoErr("client_id")); err != nil { + if t.Client, err = file.GetDb().GetClient(s.GetIntNoErr("client_id")); err != nil { s.AjaxErr(err.Error()) } - if err := file.GetCsvDb().NewTask(t); err != nil { + if err := file.GetDb().NewTask(t); err != nil { s.AjaxErr(err.Error()) } if err := server.AddTask(t); err != nil { @@ -122,7 +122,7 @@ func (s *IndexController) Add() { func (s *IndexController) GetOneTunnel() { id := s.GetIntNoErr("id") data := make(map[string]interface{}) - if t, err := file.GetCsvDb().GetTask(id); err != nil { + if t, err := file.GetDb().GetTask(id); err != nil { data["code"] = 0 } else { data["code"] = 1 @@ -134,7 +134,7 @@ func (s *IndexController) GetOneTunnel() { func (s *IndexController) Edit() { id := s.GetIntNoErr("id") if s.Ctx.Request.Method == "GET" { - if t, err := file.GetCsvDb().GetTask(id); err != nil { + if t, err := file.GetDb().GetTask(id); err != nil { s.error() } else { s.Data["t"] = t @@ -142,10 +142,10 @@ func (s *IndexController) Edit() { s.SetInfo("edit tunnel") s.display() } else { - if t, err := file.GetCsvDb().GetTask(id); err != nil { + if t, err := file.GetDb().GetTask(id); err != nil { s.error() } else { - if client, err := file.GetCsvDb().GetClient(s.GetIntNoErr("client_id")); err != nil { + if client, err := file.GetDb().GetClient(s.GetIntNoErr("client_id")); err != nil { s.AjaxErr("modified error,the client is not exist") return } else { @@ -166,7 +166,7 @@ func (s *IndexController) Edit() { t.LocalPath = s.GetString("local_path") t.StripPre = s.GetString("strip_pre") t.Remark = s.GetString("remark") - file.GetCsvDb().UpdateTask(t) + file.GetDb().UpdateTask(t) server.StopServer(t.Id) server.StartTask(t.Id) } @@ -207,7 +207,7 @@ func (s *IndexController) HostList() { } else { start, length := s.GetAjaxParams() clientId := s.GetIntNoErr("client_id") - list, cnt := file.GetCsvDb().GetHost(start, length, clientId, s.GetString("search")) + list, cnt := file.GetDb().GetHost(start, length, clientId, s.GetString("search")) s.AjaxTable(list, cnt, cnt) } } @@ -215,7 +215,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().GetHostById(s.GetIntNoErr("id")); err != nil { + if h, err := file.GetDb().GetHostById(s.GetIntNoErr("id")); err != nil { data["code"] = 0 } else { data["data"] = h @@ -228,7 +228,7 @@ func (s *IndexController) GetHost() { func (s *IndexController) DelHost() { id := s.GetIntNoErr("id") - if err := file.GetCsvDb().DelHost(id); err != nil { + if err := file.GetDb().DelHost(id); err != nil { s.AjaxErr("delete error") } s.AjaxOk("delete success") @@ -242,7 +242,7 @@ func (s *IndexController) AddHost() { s.display("index/hadd") } else { h := &file.Host{ - Id: int(file.GetCsvDb().GetHostId()), + Id: int(file.GetDb().JsonDb.GetHostId()), Host: s.GetString("host"), Target: &file.Target{TargetStr: s.GetString("target")}, HeaderChange: s.GetString("header"), @@ -253,10 +253,10 @@ func (s *IndexController) AddHost() { Scheme: s.GetString("scheme"), } var err error - if h.Client, err = file.GetCsvDb().GetClient(s.GetIntNoErr("client_id")); err != nil { + if h.Client, err = file.GetDb().GetClient(s.GetIntNoErr("client_id")); err != nil { s.AjaxErr("add error") } - if err := file.GetCsvDb().NewHost(h); err != nil { + if err := file.GetDb().NewHost(h); err != nil { s.AjaxErr("add fail" + err.Error()) } s.AjaxOk("add success") @@ -267,7 +267,7 @@ func (s *IndexController) EditHost() { id := s.GetIntNoErr("id") if s.Ctx.Request.Method == "GET" { s.Data["menu"] = "host" - if h, err := file.GetCsvDb().GetHostById(id); err != nil { + if h, err := file.GetDb().GetHostById(id); err != nil { s.error() } else { s.Data["h"] = h @@ -275,7 +275,7 @@ func (s *IndexController) EditHost() { s.SetInfo("edit") s.display("index/hedit") } else { - if h, err := file.GetCsvDb().GetHostById(id); err != nil { + if h, err := file.GetDb().GetHostById(id); err != nil { s.error() } else { if h.Host != s.GetString("host") { @@ -283,12 +283,12 @@ func (s *IndexController) EditHost() { tmpHost.Host = s.GetString("host") tmpHost.Location = s.GetString("location") tmpHost.Scheme = s.GetString("scheme") - if file.GetCsvDb().IsHostExist(tmpHost) { + if file.GetDb().IsHostExist(tmpHost) { s.AjaxErr("host has exist") return } } - if client, err := file.GetCsvDb().GetClient(s.GetIntNoErr("client_id")); err != nil { + if client, err := file.GetDb().GetClient(s.GetIntNoErr("client_id")); err != nil { s.AjaxErr("modified error,the client is not exist") } else { h.Client = client @@ -300,7 +300,7 @@ func (s *IndexController) EditHost() { h.Remark = s.GetString("remark") h.Location = s.GetString("location") h.Scheme = s.GetString("scheme") - file.GetCsvDb().StoreHostToCsv() + file.GetDb().JsonDb.StoreHostToJsonFile() } s.AjaxOk("modified success") } diff --git a/web/controllers/login.go b/web/controllers/login.go index 7359575a..90f70cdb 100755 --- a/web/controllers/login.go +++ b/web/controllers/login.go @@ -24,7 +24,7 @@ func (self *LoginController) Verify() { } b, err := beego.AppConfig.Bool("allow_user_login") if err == nil && b && !auth { - file.GetCsvDb().Clients.Range(func(key, value interface{}) bool { + file.GetDb().JsonDb.Clients.Range(func(key, value interface{}) bool { v := value.(*file.Client) if !v.Status || v.NoDisplay { return true