客户端配置,端口白名单等

This commit is contained in:
刘河
2019-02-13 03:54:00 +08:00
parent 59d789d253
commit 44d314515b
34 changed files with 1096 additions and 472 deletions

View File

@@ -1,19 +1,25 @@
package common
const (
CONN_DATA_SEQ = "*#*"
COMPRESS_NONE_ENCODE = iota
COMPRESS_NONE_DECODE
COMPRESS_SNAPY_ENCODE
COMPRESS_SNAPY_DECODE
VERIFY_EER = "vkey"
WORK_MAIN = "main"
WORK_CHAN = "chan"
RES_SIGN = "sign"
RES_MSG = "msg0"
RES_CLOSE = "clse"
NEW_CONN = "conn" //新连接标志
NEW_TASK = "task" //新连接标志
CONN_SUCCESS = "sucs"
VERIFY_EER = "vkey"
VERIFY_SUCCESS = "sucs"
WORK_MAIN = "main"
WORK_CHAN = "chan"
WORK_CONFIG = "conf"
WORK_STATUS = "stus"
RES_SIGN = "sign"
RES_MSG = "msg0"
RES_CLOSE = "clse"
NEW_CONN = "conn" //新连接标志
NEW_TASK = "task" //新连接标志
NEW_CONF = "conf" //新连接标志
NEW_HOST = "host" //新连接标志
CONN_TCP = "tcp"
CONN_UDP = "udp"
UnauthorizedBytes = `HTTP/1.1 401 Unauthorized

View File

@@ -56,7 +56,7 @@ func GetLogPath() string {
}
//interface pid file path
func GetPidPath() string {
func GetTmpPath() string {
var path string
if IsWindows() {
path = "./"

View File

@@ -144,7 +144,11 @@ func FileExists(name string) bool {
//Judge whether the TCP port can open normally
func TestTcpPort(port int) bool {
l, err := net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), port, ""})
defer l.Close()
defer func() {
if l != nil {
l.Close()
}
}()
if err != nil {
return false
}
@@ -154,7 +158,11 @@ func TestTcpPort(port int) bool {
//Judge whether the UDP port can open normally
func TestUdpPort(port int) bool {
l, err := net.ListenUDP("udp", &net.UDPAddr{net.ParseIP("0.0.0.0"), port, ""})
defer l.Close()
defer func() {
if l != nil {
l.Close()
}
}()
if err != nil {
return false
}
@@ -168,9 +176,28 @@ func BinaryWrite(raw *bytes.Buffer, v ...string) {
buffer := new(bytes.Buffer)
var l int32
for _, v := range v {
l += int32(len([]byte(v))) + int32(len([]byte("#")))
l += int32(len([]byte(v))) + int32(len([]byte(CONN_DATA_SEQ)))
binary.Write(buffer, binary.LittleEndian, []byte(v))
binary.Write(buffer, binary.LittleEndian, []byte("#"))
binary.Write(buffer, binary.LittleEndian, []byte(CONN_DATA_SEQ))
}
binary.Write(raw, binary.LittleEndian, l)
binary.Write(raw, binary.LittleEndian, buffer.Bytes())
}
func InArr(arr []string, val string) bool {
for _, v := range arr {
if v == val {
return true
}
}
return false
}
func InIntArr(arr []int, val int) bool {
for _, v := range arr {
if v == val {
return true
}
}
return false
}

158
lib/config/config.go Normal file
View File

@@ -0,0 +1,158 @@
package config
import (
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/file"
"regexp"
"strings"
)
type CommonConfig struct {
Server string
VKey string
Tp string //bridgeType kcp or tcp
AutoReconnection bool
Cnf *file.Config
}
type Config struct {
content string
title []string
CommonConfig *CommonConfig
Hosts []*file.Host
Tasks []*file.Tunnel
}
func NewConfig(path string) (c *Config, err error) {
c = new(Config)
var b []byte
if b, err = common.ReadAllFromFile(path); err != nil {
return
} else {
c.content = string(b)
if c.title, err = getAllTitle(c.content); err != nil {
return
}
var nowIndex int
var nextIndex int
var nowContent string
for i := 0; i < len(c.title); i++ {
nowIndex = strings.Index(c.content, c.title[i]) + len(c.title[i])
if i < len(c.title)-1 {
nextIndex = strings.Index(c.content, c.title[i+1])
} else {
nextIndex = len(c.content)
}
nowContent = c.content[nowIndex:nextIndex]
switch c.title[i] {
case "[common]":
c.CommonConfig = dealCommon(nowContent)
default:
if strings.Index(nowContent, "host") > -1 {
h := dealHost(nowContent)
h.Remark = getTitleContent(c.title[i])
c.Hosts = append(c.Hosts, h)
} else {
t := dealTunnel(nowContent)
t.Remark = getTitleContent(c.title[i])
c.Tasks = append(c.Tasks, t)
}
}
}
}
return
}
func getTitleContent(s string) string {
re, _ := regexp.Compile(`[\[\]]`)
return re.ReplaceAllString(s, "")
}
func dealCommon(s string) *CommonConfig {
c := &CommonConfig{}
c.Cnf = new(file.Config)
for _, v := range strings.Split(s, "\n") {
item := strings.Split(v, "=")
if len(item) == 0 {
continue
} else if len(item) == 1 {
item = append(item, "")
}
switch item[0] {
case "server":
c.Server = item[1]
case "vkey":
c.VKey = item[1]
case "tp":
c.Tp = item[1]
case "auto_reconnection":
c.AutoReconnection = common.GetBoolByStr(item[1])
case "username":
c.Cnf.U = item[1]
case "password":
c.Cnf.P = item[1]
case "compress":
c.Cnf.Compress = item[1]
case "crypt":
c.Cnf.Crypt = common.GetBoolByStr(item[1])
}
}
return c
}
func dealHost(s string) *file.Host {
h := &file.Host{}
var headerChange string
for _, v := range strings.Split(s, "\n") {
item := strings.Split(v, "=")
if len(item) == 0 {
continue
} else if len(item) == 1 {
item = append(item, "")
}
switch item[0] {
case "host":
h.Host = item[1]
case "target":
h.Target = strings.Replace(item[1], ",", "\n", -1)
case "host_change":
h.HostChange = item[1]
default:
if strings.Contains(item[0], "header") {
headerChange += strings.Replace(item[0], "header_", "", -1) + ":" + item[1] + "\n"
}
h.HeaderChange = headerChange
}
}
return h
}
func dealTunnel(s string) *file.Tunnel {
t := &file.Tunnel{}
for _, v := range strings.Split(s, "\n") {
item := strings.Split(v, "=")
if len(item) == 0 {
continue
} else if len(item) == 1 {
item = append(item, "")
}
switch item[0] {
case "port":
t.Port = common.GetIntNoErrByStr(item[1])
case "mode":
t.Mode = item[1]
case "target":
t.Target = item[1]
}
}
return t
}
func getAllTitle(content string) (arr []string, err error) {
var re *regexp.Regexp
re, err = regexp.Compile(`\[.+?\]`)
if err != nil {
return
}
arr = re.FindAllString(content, -1)
return
}

69
lib/config/config_test.go Normal file
View File

@@ -0,0 +1,69 @@
package config
import (
"log"
"regexp"
"testing"
)
func TestReg(t *testing.T) {
content := `
[common]
server=127.0.0.1:8284
tp=tcp
vkey=123
[web2]
host=www.baidu.com
host_change=www.sina.com
target=127.0.0.1:8080,127.0.0.1:8082
header_cookkile=122123
header_user-Agent=122123
[web2]
host=www.baidu.com
host_change=www.sina.com
target=127.0.0.1:8080,127.0.0.1:8082
header_cookkile="122123"
header_user-Agent=122123
[tunnel1]
type=udp
target=127.0.0.1:8080
port=9001
compress=snappy
crypt=true
u=1
p=2
[tunnel2]
type=tcp
target=127.0.0.1:8080
port=9001
compress=snappy
crypt=true
u=1
p=2
`
re, err := regexp.Compile(`\[.+?\]`)
if err != nil {
t.Fail()
}
log.Println(re.FindAllString(content, -1))
}
func TestDealCommon(t *testing.T) {
s := `server=127.0.0.1:8284
tp=tcp
vkey=123`
f := new(CommonConfig)
f.Server = "127.0.0.1:8284"
f.Tp = "tcp"
f.VKey = "123"
if c := dealCommon(s); *c != *f {
t.Fail()
}
}
func TestGetTitleContent(t *testing.T) {
s := "[common]"
if getTitleContent(s) != "common" {
t.Fail()
}
}

View File

@@ -264,6 +264,98 @@ func (s *Conn) GetLinkInfo() (lk *Link, err error) {
return
}
//send host info
func (s *Conn) SendHostInfo(h *file.Host) (int, error) {
/*
The task info is formed as follows:
+----+-----+---------+
|type| len | content |
+----+---------------+
| 4 | 4 | ... |
+----+---------------+
*/
raw := bytes.NewBuffer([]byte{})
binary.Write(raw, binary.LittleEndian, []byte(common.NEW_HOST))
common.BinaryWrite(raw, h.Host, h.Target, h.HeaderChange, h.HostChange, h.Remark)
s.Lock()
defer s.Unlock()
return s.Write(raw.Bytes())
}
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
var b []byte
if l, err = s.GetLen(); err != nil {
return
} else if b, err = s.ReadLen(l); err != nil {
return
} else {
arr := strings.Split(string(b), common.CONN_DATA_SEQ)
h = new(file.Host)
h.Host = arr[0]
h.Target = arr[1]
h.HeaderChange = arr[2]
h.HostChange = arr[3]
h.Remark = arr[4]
h.Flow = new(file.Flow)
h.NoStore = true
}
return
}
//send task info
func (s *Conn) SendConfigInfo(c *file.Config) (int, error) {
/*
The task info is formed as follows:
+----+-----+---------+
|type| len | content |
+----+---------------+
| 4 | 4 | ... |
+----+---------------+
*/
raw := bytes.NewBuffer([]byte{})
binary.Write(raw, binary.LittleEndian, []byte(common.NEW_CONF))
common.BinaryWrite(raw, c.U, c.P, common.GetStrByBool(c.Crypt), c.Compress)
s.Lock()
defer s.Unlock()
return s.Write(raw.Bytes())
}
//get task info
func (s *Conn) GetConfigInfo() (c *file.Config, err error) {
var l int
var b []byte
if l, err = s.GetLen(); err != nil {
return
} else if b, err = s.ReadLen(l); err != nil {
return
} else {
arr := strings.Split(string(b), common.CONN_DATA_SEQ)
c = new(file.Config)
c.U = arr[0]
c.P = arr[1]
c.Crypt = common.GetBoolByStr(arr[2])
c.Compress = arr[3]
c.CompressDecode, c.CompressDecode = common.GetCompressType(arr[3])
}
return
}
//send task info
func (s *Conn) SendTaskInfo(t *file.Tunnel) (int, error) {
/*
@@ -275,8 +367,8 @@ func (s *Conn) SendTaskInfo(t *file.Tunnel) (int, error) {
+----+---------------+
*/
raw := bytes.NewBuffer([]byte{})
binary.Write(raw, binary.LittleEndian, common.NEW_TASK)
common.BinaryWrite(raw, t.Mode, string(t.TcpPort), string(t.Target), string(t.Config.U), string(t.Config.P), common.GetStrByBool(t.Config.Crypt), t.Config.Compress, t.Remark)
binary.Write(raw, binary.LittleEndian, []byte(common.NEW_TASK))
common.BinaryWrite(raw, t.Mode, strconv.Itoa(t.Port), t.Target, t.Remark)
s.Lock()
defer s.Unlock()
return s.Write(raw.Bytes())
@@ -291,23 +383,16 @@ func (s *Conn) GetTaskInfo() (t *file.Tunnel, err error) {
} else if b, err = s.ReadLen(l); err != nil {
return
} else {
arr := strings.Split(string(b), "#")
arr := strings.Split(string(b), common.CONN_DATA_SEQ)
t = new(file.Tunnel)
t.Mode = arr[0]
t.TcpPort, _ = strconv.Atoi(arr[1])
t.Port, _ = strconv.Atoi(arr[1])
t.Target = arr[2]
t.Config = new(file.Config)
t.Config.U = arr[3]
t.Config.P = arr[4]
t.Config.Compress = arr[5]
t.Config.CompressDecode, t.Config.CompressDecode = common.GetCompressType(arr[5])
t.Id = file.GetCsvDb().GetTaskId()
t.Status = true
if t.Client, err = file.GetCsvDb().GetClient(0); err != nil {
return
}
t.Flow = new(file.Flow)
t.Remark = arr[6]
t.UseClientCnf = false
t.Remark = arr[3]
t.NoStore = true
}
return
}
@@ -369,6 +454,13 @@ func (s *Conn) WriteMain() (int, error) {
return s.Write([]byte(common.WORK_MAIN))
}
//write main
func (s *Conn) WriteConfig() (int, error) {
s.Lock()
defer s.Unlock()
return s.Write([]byte(common.WORK_CONFIG))
}
//write chan
func (s *Conn) WriteChan() (int, error) {
s.Lock()

View File

@@ -18,6 +18,7 @@ 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 {

View File

@@ -45,20 +45,17 @@ func (s *Csv) StoreTasksToCsv() {
defer csvFile.Close()
writer := csv.NewWriter(csvFile)
for _, task := range s.Tasks {
if task.NoStore {
continue
}
lg.Println(task)
record := []string{
strconv.Itoa(task.TcpPort),
strconv.Itoa(task.Port),
task.Mode,
task.Target,
task.Config.U,
task.Config.P,
task.Config.Compress,
common.GetStrByBool(task.Status),
common.GetStrByBool(task.Config.Crypt),
strconv.Itoa(task.Config.CompressEncode),
strconv.Itoa(task.Config.CompressDecode),
strconv.Itoa(task.Id),
strconv.Itoa(task.Client.Id),
strconv.FormatBool(task.UseClientCnf),
task.Remark,
}
err := writer.Write(record)
@@ -97,24 +94,15 @@ func (s *Csv) LoadTaskFromCsv() {
// 将每一行数据保存到内存slice中
for _, item := range records {
post := &Tunnel{
TcpPort: common.GetIntNoErrByStr(item[0]),
Mode: item[1],
Target: item[2],
Config: &Config{
U: item[3],
P: item[4],
Compress: item[5],
Crypt: common.GetBoolByStr(item[7]),
CompressEncode: common.GetIntNoErrByStr(item[8]),
CompressDecode: common.GetIntNoErrByStr(item[9]),
},
Status: common.GetBoolByStr(item[6]),
Id: common.GetIntNoErrByStr(item[10]),
UseClientCnf: common.GetBoolByStr(item[12]),
Remark: item[13],
Port: common.GetIntNoErrByStr(item[0]),
Mode: item[1],
Target: item[2],
Status: common.GetBoolByStr(item[3]),
Id: common.GetIntNoErrByStr(item[4]),
Remark: item[6],
}
post.Flow = new(Flow)
if post.Client, err = s.GetClient(common.GetIntNoErrByStr(item[11])); err != nil {
if post.Client, err = s.GetClient(common.GetIntNoErrByStr(item[5])); err != nil {
continue
}
tasks = append(tasks, post)
@@ -197,6 +185,9 @@ func (s *Csv) StoreHostToCsv() {
// 将map中的Post转换成slice因为csv的Write需要slice参数
// 并写入csv文件
for _, host := range s.Hosts {
if host.NoStore {
continue
}
record := []string{
host.Host,
host.Target,
@@ -286,11 +277,22 @@ func (s *Csv) DelHost(host string) error {
return errors.New("不存在")
}
func (s *Csv) IsHostExist(host string) bool {
for _, v := range s.Hosts {
if v.Host == host {
return true
}
}
return false
}
func (s *Csv) NewHost(t *Host) {
if s.IsHostExist(t.Host) {
return
}
t.Flow = new(Flow)
s.Hosts = append(s.Hosts, t)
s.StoreHostToCsv()
}
func (s *Csv) UpdateHost(t *Host) error {
@@ -333,9 +335,12 @@ func (s *Csv) DelClient(id int) error {
}
func (s *Csv) NewClient(c *Client) {
if c.Id == 0 {
c.Id = s.GetClientId()
}
c.Flow = new(Flow)
s.Lock()
defer s.Unlock()
c.Flow = new(Flow)
s.Clients = append(s.Clients, c)
s.StoreClientsToCsv()
}
@@ -369,6 +374,9 @@ func (s *Csv) GetClientList(start, length int) ([]*Client, int) {
list := make([]*Client, 0)
var cnt int
for _, v := range s.Clients {
if v.NoDisplay {
continue
}
cnt++
if start--; start < 0 {
if length--; length > 0 {
@@ -385,10 +393,32 @@ func (s *Csv) GetClient(id int) (v *Client, err error) {
return
}
}
err = errors.New("未找到")
err = errors.New("未找到客户端")
return
}
func (s *Csv) GetClientIdByVkey(vkey string) (id int, err error) {
for _, v := range s.Clients {
if v.VerifyKey == vkey {
id = v.Id
return
}
}
err = errors.New("未找到客户端")
return
}
//get key by host from x
func (s *Csv) GetInfoByHost(host string) (h *Host, err error) {
for _, v := range s.Hosts {
s := strings.Split(host, ":")
if s[0] == v.Host {
h = v
return
}
}
err = errors.New("未找到host对应的内网目标")
return
}
func (s *Csv) StoreClientsToCsv() {
// 创建文件
csvFile, err := os.Create(filepath.Join(s.RunPath, "conf", "clients.csv"))
@@ -398,6 +428,9 @@ func (s *Csv) StoreClientsToCsv() {
defer csvFile.Close()
writer := csv.NewWriter(csvFile)
for _, client := range s.Clients {
if client.NoStore {
continue
}
record := []string{
strconv.Itoa(client.Id),
client.VerifyKey,

View File

@@ -31,10 +31,30 @@ type Client struct {
RateLimit int //速度限制 /kb
Flow *Flow //流量
Rate *rate.Rate //速度控制
NoStore bool
NoDisplay bool
id int
sync.RWMutex
}
func NewClient(vKey string, noStore bool, noDisplay bool) *Client {
return &Client{
Cnf: new(Config),
Id: 0,
VerifyKey: vKey,
Addr: "",
Remark: "",
Status: true,
IsConnect: false,
RateLimit: 0,
Flow: new(Flow),
Rate: nil,
NoStore: noStore,
id: GetCsvDb().GetClientId(),
RWMutex: sync.RWMutex{},
NoDisplay: noDisplay,
}
}
func (s *Client) GetId() int {
s.Lock()
defer s.Unlock()
@@ -43,16 +63,16 @@ func (s *Client) GetId() int {
}
type Tunnel struct {
Id int //Id
TcpPort int //服务端监听端口
Mode string //启动方式
Target string //目标
Status bool //是否开启
Client *Client //所属客户端id
Flow *Flow
Config *Config
UseClientCnf bool //是否继承客户端配置
Remark string //备注
Id int //Id
Port int //服务端监听端口
Mode string //启动方式
Target string //目标
Status bool //设置是否开启
RunStatus bool //当前运行状态
Client *Client //所属客户端id
Flow *Flow
Remark string //备注
NoStore bool
}
type Config struct {
@@ -74,6 +94,7 @@ type Host struct {
Remark string //备注
NowIndex int
TargetArr []string
NoStore bool
sync.RWMutex
}

View File

@@ -121,7 +121,7 @@ doLit:
//
// This always copies 16 bytes, instead of only length bytes, but that's
// OK. If the input is a valid Snappy encoding then subsequent iterations
// will fix up the overrun. Otherwise, Decode returns a nil []byte (and a
// will fix up the overserver. Otherwise, Decode returns a nil []byte (and a
// non-nil error), so the overrun will be ignored.
//
// Note that on amd64, it is legal and cheap to issue unaligned 8-byte or

View File

@@ -473,7 +473,7 @@ emitLiteralFastPath:
// (Encode's documentation says that dst and src must not overlap.)
//
// This always copies 16 bytes, instead of only len(lit) bytes, but that's
// OK. Subsequent iterations will fix up the overrun.
// OK. Subsequent iterations will fix up the overserver.
//
// Note that on amd64, it is legal and cheap to issue unaligned 8-byte or
// 16-byte loads and stores. This technique probably wouldn't be as