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

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,4 +1,4 @@
package server
package proxy
import (
"errors"
@@ -17,7 +17,6 @@ type server struct {
id int
bridge *bridge.Bridge
task *file.Tunnel
config *file.Config
errorContent []byte
sync.Mutex
}
@@ -36,39 +35,6 @@ func (s *server) FlowAddHost(host *file.Host, in, out int64) {
host.Flow.InletFlow += in
}
//热更新配置
func (s *server) ResetConfig() bool {
//获取最新数据
task, err := file.GetCsvDb().GetTask(s.task.Id)
if err != nil {
return false
}
if s.task.Client.Flow.FlowLimit > 0 && (s.task.Client.Flow.FlowLimit<<20) < (s.task.Client.Flow.ExportFlow+s.task.Client.Flow.InletFlow) {
return false
}
s.task.UseClientCnf = task.UseClientCnf
//使用客户端配置
client, err := file.GetCsvDb().GetClient(s.task.Client.Id)
if s.task.UseClientCnf {
if err == nil {
s.config.U = client.Cnf.U
s.config.P = client.Cnf.P
s.config.Compress = client.Cnf.Compress
s.config.Crypt = client.Cnf.Crypt
}
} else {
if err == nil {
s.config.U = task.Config.U
s.config.P = task.Config.P
s.config.Compress = task.Config.Compress
s.config.Crypt = task.Config.Crypt
}
}
s.task.Client.Rate = client.Rate
s.config.CompressDecode, s.config.CompressEncode = common.GetCompressType(s.config.Compress)
return true
}
func (s *server) linkCopy(link *conn.Link, c *conn.Conn, rb []byte, tunnel *conn.Conn, flow *file.Flow) {
if rb != nil {
if _, err := tunnel.SendMsg(rb, link); err != nil {
@@ -80,6 +46,10 @@ func (s *server) linkCopy(link *conn.Link, c *conn.Conn, rb []byte, tunnel *conn
buf := pool.BufPoolCopy.Get().([]byte)
for {
if err := s.checkFlow(); err != nil {
c.Close()
break
}
if n, err := c.Read(buf); err != nil {
tunnel.SendMsg([]byte(common.IO_EOF), link)
break
@@ -108,3 +78,10 @@ func (s *server) auth(r *http.Request, c *conn.Conn, u, p string) error {
}
return nil
}
func (s *server) checkFlow() error {
if s.task.Client.Flow.FlowLimit > 0 && (s.task.Client.Flow.FlowLimit<<20) < (s.task.Client.Flow.ExportFlow+s.task.Client.Flow.InletFlow) {
return errors.New("Traffic exceeded")
}
return nil
}

View File

@@ -1,14 +1,14 @@
package server
package proxy
import (
"bufio"
"crypto/tls"
"github.com/cnlh/nps/lib/beego"
"github.com/cnlh/nps/bridge"
"github.com/cnlh/nps/lib/beego"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/conn"
"github.com/cnlh/nps/lib/file"
"github.com/cnlh/nps/lib/lg"
"github.com/cnlh/nps/lib/common"
"log"
"net/http"
"net/http/httputil"
@@ -55,7 +55,7 @@ func (s *httpServer) Start() error {
if s.httpPort > 0 {
http = s.NewServer(s.httpPort)
go func() {
lg.Println("启动http监听,端口为", s.httpPort)
lg.Println("Start http listener, port is", s.httpPort)
err := http.ListenAndServe()
if err != nil {
lg.Fatalln(err)
@@ -64,14 +64,14 @@ func (s *httpServer) Start() error {
}
if s.httpsPort > 0 {
if !common.FileExists(s.pemPath) {
lg.Fatalf("ssl certFile文件%s不存在", s.pemPath)
lg.Fatalf("ssl certFile %s is not exist", s.pemPath)
}
if !common.FileExists(s.keyPath) {
lg.Fatalf("ssl keyFile文件%s不存在", s.keyPath)
lg.Fatalf("ssl keyFile %s exist", s.keyPath)
}
https = s.NewServer(s.httpsPort)
go func() {
lg.Println("启动https监听,端口为", s.httpsPort)
lg.Println("Start https listener, port is", s.httpsPort)
err := https.ListenAndServeTLS(s.pemPath, s.keyPath)
if err != nil {
lg.Fatalln(err)
@@ -111,7 +111,7 @@ func (s *httpServer) process(c *conn.Conn, r *http.Request) {
//多客户端域名代理
var (
isConn = true
lk *conn.Link
lk *conn.Link
host *file.Host
tunnel *conn.Conn
err error
@@ -119,7 +119,7 @@ func (s *httpServer) process(c *conn.Conn, r *http.Request) {
for {
//首次获取conn
if isConn {
if host, err = GetInfoByHost(r.Host); err != nil {
if host, err = file.GetCsvDb().GetInfoByHost(r.Host); err != nil {
lg.Printf("the host %s is not found !", r.Host)
break
}

View File

@@ -1,4 +1,4 @@
package server
package proxy
import (
"encoding/binary"
@@ -142,7 +142,7 @@ func (s *Sock5ModeServer) doConnect(c net.Conn, command uint8) {
} else {
ltype = common.CONN_TCP
}
link := conn.NewLink(s.task.Client.GetId(), ltype, addr, s.config.CompressEncode, s.config.CompressDecode, s.config.Crypt, conn.NewConn(c), s.task.Flow, nil, s.task.Client.Rate, nil)
link := conn.NewLink(s.task.Client.GetId(), ltype, addr, s.task.Client.Cnf.CompressEncode, s.task.Client.Cnf.CompressDecode, s.task.Client.Cnf.Crypt, conn.NewConn(c), s.task.Flow, nil, s.task.Client.Rate, nil)
if tunnel, err := s.bridge.SendLinkInfo(s.task.Client.Id, link); err != nil {
c.Close()
@@ -245,7 +245,7 @@ func (s *Sock5ModeServer) Auth(c net.Conn) error {
if _, err := io.ReadAtLeast(c, pass, passLen); err != nil {
return err
}
if string(pass) == s.config.U && string(user) == s.config.P {
if string(pass) == s.task.Client.Cnf.U && string(user) == s.task.Client.Cnf.P {
if _, err := c.Write([]byte{userAuthVersion, authSuccess}); err != nil {
return err
}
@@ -262,7 +262,7 @@ func (s *Sock5ModeServer) Auth(c net.Conn) error {
//start
func (s *Sock5ModeServer) Start() error {
var err error
s.listener, err = net.Listen("tcp", ":"+strconv.Itoa(s.task.TcpPort))
s.listener, err = net.Listen("tcp", ":"+strconv.Itoa(s.task.Port))
if err != nil {
return err
}
@@ -274,10 +274,6 @@ func (s *Sock5ModeServer) Start() error {
}
lg.Fatalln("accept error: ", err)
}
if !s.ResetConfig() {
conn.Close()
continue
}
go s.handleConn(conn)
}
return nil
@@ -293,8 +289,7 @@ func NewSock5ModeServer(bridge *bridge.Bridge, task *file.Tunnel) *Sock5ModeServ
s := new(Sock5ModeServer)
s.bridge = bridge
s.task = task
s.config = file.DeepCopyConfig(task.Config)
if s.config.U != "" && s.config.P != "" {
if s.task.Client.Cnf.U != "" && s.task.Client.Cnf.P != "" {
s.isVerify = true
} else {
s.isVerify = false

View File

@@ -1,9 +1,9 @@
package server
package proxy
import (
"errors"
"github.com/cnlh/nps/lib/beego"
"github.com/cnlh/nps/bridge"
"github.com/cnlh/nps/lib/beego"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/conn"
"github.com/cnlh/nps/lib/file"
@@ -25,14 +25,13 @@ func NewTunnelModeServer(process process, bridge *bridge.Bridge, task *file.Tunn
s.bridge = bridge
s.process = process
s.task = task
s.config = file.DeepCopyConfig(task.Config)
return s
}
//开始
func (s *TunnelModeServer) Start() error {
var err error
s.listener, err = net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), s.task.TcpPort, ""})
s.listener, err = net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), s.task.Port, ""})
if err != nil {
return err
}
@@ -77,14 +76,14 @@ type WebServer struct {
func (s *WebServer) Start() error {
p, _ := beego.AppConfig.Int("httpport")
if !common.TestTcpPort(p) {
lg.Fatalln("web管理端口", p, "被占用!")
lg.Fatalf("Web management port %d is occupied", p)
}
beego.BConfig.WebConfig.Session.SessionOn = true
lg.Println("web管理启动,访问端口为", p)
lg.Println("Web management start, access port is", p)
beego.SetStaticPath("/static", filepath.Join(common.GetRunPath(), "web", "static"))
beego.SetViewsPath(filepath.Join(common.GetRunPath(), "web", "views"))
beego.Run()
return errors.New("web管理启动失败")
return errors.New("Web management startup failure")
}
//new
@@ -98,26 +97,18 @@ type process func(c *conn.Conn, s *TunnelModeServer) error
//tcp隧道模式
func ProcessTunnel(c *conn.Conn, s *TunnelModeServer) error {
if !s.ResetConfig() {
c.Close()
return errors.New("流量超出")
}
return s.dealClient(c, s.config, s.task.Target, "", nil)
return s.dealClient(c, s.task.Client.Cnf, s.task.Target, "", nil)
}
//http代理模式
func ProcessHttp(c *conn.Conn, s *TunnelModeServer) error {
if !s.ResetConfig() {
c.Close()
return errors.New("流量超出")
}
method, addr, rb, err, r := c.GetHost()
if err != nil {
c.Close()
return err
}
if err := s.auth(r, c, s.config.U, s.config.P); err != nil {
if err := s.auth(r, c, s.task.Client.Cnf.U, s.task.Client.Cnf.P); err != nil {
return err
}
return s.dealClient(c, s.config, addr, method, rb)
return s.dealClient(c, s.task.Client.Cnf, addr, method, rb)
}

View File

@@ -1,4 +1,4 @@
package server
package proxy
import (
"github.com/cnlh/nps/bridge"
@@ -21,14 +21,13 @@ func NewUdpModeServer(bridge *bridge.Bridge, task *file.Tunnel) *UdpModeServer {
s.bridge = bridge
s.udpMap = make(map[string]*conn.Conn)
s.task = task
s.config = file.DeepCopyConfig(task.Config)
return s
}
//开始
func (s *UdpModeServer) Start() error {
var err error
s.listener, err = net.ListenUDP("udp", &net.UDPAddr{net.ParseIP("0.0.0.0"), s.task.TcpPort, ""})
s.listener, err = net.ListenUDP("udp", &net.UDPAddr{net.ParseIP("0.0.0.0"), s.task.Port, ""})
if err != nil {
return err
}
@@ -41,17 +40,16 @@ func (s *UdpModeServer) Start() error {
}
continue
}
if !s.ResetConfig() {
continue
}
go s.process(addr, buf[:n])
}
return nil
}
func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) {
link := conn.NewLink(s.task.Client.GetId(), common.CONN_UDP, s.task.Target, s.config.CompressEncode, s.config.CompressDecode, s.config.Crypt, nil, s.task.Flow, s.listener, s.task.Client.Rate, addr)
link := conn.NewLink(s.task.Client.GetId(), common.CONN_UDP, s.task.Target, s.task.Client.Cnf.CompressEncode, s.task.Client.Cnf.CompressDecode, s.task.Client.Cnf.Crypt, nil, s.task.Flow, s.listener, s.task.Client.Rate, addr)
if err := s.checkFlow(); err != nil {
return
}
if tunnel, err := s.bridge.SendLinkInfo(s.task.Client.Id, link); err != nil {
return
} else {

View File

@@ -3,15 +3,17 @@ package server
import (
"errors"
"github.com/cnlh/nps/bridge"
"github.com/cnlh/nps/lib/beego"
"github.com/cnlh/nps/lib/file"
"github.com/cnlh/nps/lib/lg"
"github.com/cnlh/nps/server/proxy"
"github.com/cnlh/nps/server/tool"
"reflect"
"strings"
)
var (
Bridge *bridge.Bridge
RunList map[int]interface{} //运行中的任务
Bridge *bridge.Bridge
RunList map[int]interface{} //运行中的任务
)
func init() {
@@ -20,20 +22,39 @@ func init() {
//从csv文件中恢复任务
func InitFromCsv() {
//Add a public password
c := file.NewClient(beego.AppConfig.String("publicVkey"), true, true)
file.GetCsvDb().NewClient(c)
RunList[c.Id] = nil
//Initialize services in server-side files
for _, v := range file.GetCsvDb().Tasks {
if v.Status {
lg.Println("启动模式:", v.Mode, "监听端口:", v.TcpPort)
lg.Println("启动模式:", v.Mode, "监听端口:", v.Port)
AddTask(v)
}
}
}
func DealBridgeTask() {
for {
select {
case t := <-Bridge.OpenTask:
AddTask(t)
case id := <-Bridge.CloseClient:
DelTunnelAndHostByClientId(id)
file.GetCsvDb().DelClient(id)
}
}
}
//start a new server
func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string) {
Bridge = bridge.NewTunnel(bridgePort, RunList, bridgeType)
Bridge = bridge.NewTunnel(bridgePort, bridgeType)
if err := Bridge.StartTunnel(); err != nil {
lg.Fatalln("服务端开启失败", err)
} else {
lg.Printf("Server startup, the bridge type is %s, the bridge port is %d", bridgeType, bridgePort)
}
go DealBridgeTask()
if svr := NewMode(Bridge, cnf); svr != nil {
RunList[cnf.Id] = svr
err := reflect.ValueOf(svr).MethodByName("Start").Call(nil)[0]
@@ -41,7 +62,7 @@ func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string) {
lg.Fatalln(err)
}
} else {
lg.Fatalln("启动模式不正确")
lg.Fatalln("启动模式%s不正确", cnf.Mode)
}
}
@@ -49,26 +70,25 @@ func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string) {
func NewMode(Bridge *bridge.Bridge, c *file.Tunnel) interface{} {
switch c.Mode {
case "tunnelServer":
return NewTunnelModeServer(ProcessTunnel, Bridge, c)
return proxy.NewTunnelModeServer(proxy.ProcessTunnel, Bridge, c)
case "socks5Server":
return NewSock5ModeServer(Bridge, c)
return proxy.NewSock5ModeServer(Bridge, c)
case "httpProxyServer":
return NewTunnelModeServer(ProcessHttp, Bridge, c)
return proxy.NewTunnelModeServer(proxy.ProcessHttp, Bridge, c)
case "udpServer":
return NewUdpModeServer(Bridge, c)
return proxy.NewUdpModeServer(Bridge, c)
case "webServer":
InitFromCsv()
t := &file.Tunnel{
TcpPort: 0,
Mode: "httpHostServer",
Target: "",
Config: &file.Config{},
Status: true,
Port: 0,
Mode: "httpHostServer",
Target: "",
Status: true,
}
AddTask(t)
return NewWebServer(Bridge)
return proxy.NewWebServer(Bridge)
case "httpHostServer":
return NewHttp(Bridge, c)
return proxy.NewHttp(Bridge, c)
}
return nil
}
@@ -83,6 +103,7 @@ func StopServer(id int) error {
t.Status = false
file.GetCsvDb().UpdateTask(t)
}
delete(RunList, id)
return nil
}
return errors.New("未在运行中")
@@ -90,17 +111,22 @@ func StopServer(id int) error {
//add task
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")
}
if svr := NewMode(Bridge, t); svr != nil {
RunList[t.Id] = svr
go func() {
err := reflect.ValueOf(svr).MethodByName("Start").Call(nil)[0]
if err.Interface() != nil {
lg.Fatalln("客户端", t.Id, "启动失败,错误:", err)
lg.Println("clientId %d taskId %d start error %s", t.Client.Id, t.Id, err)
delete(RunList, t.Id)
return
}
}()
} else {
return errors.New("启动模式不正确")
return errors.New("the mode is not correct")
}
return nil
}
@@ -119,23 +145,12 @@ func StartTask(id int) error {
//delete task
func DelTask(id int) error {
if err := StopServer(id); err != nil {
return err
}
return file.GetCsvDb().DelTask(id)
}
//get key by host from x
func GetInfoByHost(host string) (h *file.Host, err error) {
for _, v := range file.GetCsvDb().Hosts {
s := strings.Split(host, ":")
if s[0] == v.Host {
h = v
return
if _, ok := RunList[id]; ok {
if err := StopServer(id); err != nil {
return err
}
}
err = errors.New("未找到host对应的内网目标")
return
return file.GetCsvDb().DelTask(id)
}
//get task list by page num
@@ -155,9 +170,9 @@ func GetTunnel(start, length int, typeVal string, clientId int) ([]*file.Tunnel,
if start--; start < 0 {
if length--; length > 0 {
if _, ok := RunList[v.Id]; ok {
v.Client.Status = true
v.RunStatus = true
} else {
v.Client.Status = false
v.RunStatus = false
}
list = append(list, v)
}
@@ -200,11 +215,15 @@ func dealClientData(list []*file.Client) {
//根据客户端id删除其所属的所有隧道和域名
func DelTunnelAndHostByClientId(clientId int) {
var ids []int
for _, v := range file.GetCsvDb().Tasks {
if v.Client.Id == clientId {
DelTask(v.Id)
ids = append(ids, v.Id)
}
}
for _, id := range ids {
DelTask(id)
}
for _, v := range file.GetCsvDb().Hosts {
if v.Client.Id == clientId {
file.GetCsvDb().DelHost(v.Host)

View File

@@ -1,4 +1,4 @@
package server
package test
import (
"github.com/cnlh/nps/lib/beego"
@@ -13,9 +13,9 @@ func TestServerConfig() {
var postUdpArr []int
for _, v := range file.GetCsvDb().Tasks {
if v.Mode == "udpServer" {
isInArr(&postUdpArr, v.TcpPort, v.Remark, "udp")
isInArr(&postUdpArr, v.Port, v.Remark, "udp")
} else {
isInArr(&postTcpArr, v.TcpPort, v.Remark, "tcp")
isInArr(&postTcpArr, v.Port, v.Remark, "tcp")
}
}
p, err := beego.AppConfig.Int("httpport")

55
server/tool/utils.go Normal file
View File

@@ -0,0 +1,55 @@
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
}
func TestServerPort(p int, m string) (b bool) {
if len(ports) != 0 {
if !common.InIntArr(ports, p) {
return false
}
}
if m == "udpServer" {
b = common.TestUdpPort(p)
} else {
b = common.TestTcpPort(p)
}
return
}