瀏覽代碼

pugin init

刘河 5 年之前
父節點
當前提交
e11511637b
共有 9 個文件被更改,包括 265 次插入1 次删除
  1. 2 0
      conf/clients.json
  2. 2 0
      conf/hosts.json
  3. 1 1
      conf/nps.conf
  4. 3 0
      conf/tasks.json
  5. 34 0
      core/struct.go
  6. 36 0
      module.md
  7. 1 0
      server/proxy/socks5.go
  8. 128 0
      server/socks5/socks5_access_handle.go
  9. 58 0
      server/socks5/socks5_handshake_handle.go

+ 2 - 0
conf/clients.json

@@ -0,0 +1,2 @@
+{"Cnf":{"U":"","P":"","Compress":false,"Crypt":false},"Id":2,"VerifyKey":"m3ue28maxy3pgqp8","Addr":"","Remark":"","Status":true,"IsConnect":false,"RateLimit":0,"Flow":{"ExportFlow":0,"InletFlow":0,"FlowLimit":0},"Rate":{"NowRate":0},"NoStore":false,"NoDisplay":false,"MaxConn":0,"NowConn":0,"WebUserName":"","WebPassword":"","ConfigConnAllow":true,"MaxTunnelNum":0}
+*#*

+ 2 - 0
conf/hosts.json

@@ -0,0 +1,2 @@
+{"Id":1,"Host":"a.o.com","HeaderChange":"","HostChange":"","Location":"/","Remark":"","Scheme":"all","CertFilePath":"","KeyFilePath":"","NoStore":false,"IsClose":false,"Flow":{"ExportFlow":0,"InletFlow":0,"FlowLimit":0},"Client":{"Cnf":{"U":"","P":"","Compress":false,"Crypt":false},"Id":2,"VerifyKey":"m3ue28maxy3pgqp8","Addr":"127.0.0.1","Remark":"","Status":true,"IsConnect":true,"RateLimit":0,"Flow":{"ExportFlow":0,"InletFlow":0,"FlowLimit":0},"Rate":{"NowRate":0},"NoStore":false,"NoDisplay":false,"MaxConn":0,"NowConn":0,"WebUserName":"","WebPassword":"","ConfigConnAllow":true,"MaxTunnelNum":0},"Target":{"TargetStr":"127.0.0.1:8080","TargetArr":null,"LocalProxy":false}}
+*#*

+ 1 - 1
conf/nps.conf

@@ -4,7 +4,7 @@ runmode = dev
 
 #HTTP(S) proxy port, no startup if empty
 http_proxy_ip=0.0.0.0
-http_proxy_port=80
+http_proxy_port=809
 https_proxy_port=443
 https_just_proxy=true
 #default https certificate setting

+ 3 - 0
conf/tasks.json

@@ -0,0 +1,3 @@
+{"Id":2,"Port":1234,"ServerIp":"","Mode":"tcp","Status":true,"RunStatus":true,"Client":{"Cnf":{"U":"","P":"","Compress":false,"Crypt":false},"Id":2,"VerifyKey":"m3ue28maxy3pgqp8","Addr":"","Remark":"","Status":true,"IsConnect":false,"RateLimit":0,"Flow":{"ExportFlow":0,"InletFlow":0,"FlowLimit":0},"Rate":{"NowRate":0},"NoStore":false,"NoDisplay":false,"MaxConn":0,"NowConn":0,"WebUserName":"","WebPassword":"","ConfigConnAllow":true,"MaxTunnelNum":0},"Ports":"","Flow":{"ExportFlow":0,"InletFlow":0,"FlowLimit":0},"Password":"","Remark":"","TargetAddr":"","NoStore":false,"LocalPath":"","StripPre":"","Target":{"TargetStr":"152.136.18.138:22","TargetArr":null,"LocalProxy":false},"HealthCheckTimeout":0,"HealthMaxFail":0,"HealthCheckInterval":0,"HealthNextTime":"0001-01-01T00:00:00Z","HealthMap":null,"HttpHealthUrl":"","HealthRemoveArr":null,"HealthCheckType":"","HealthCheckTarget":""}
+*#*{"Id":3,"Port":1111,"ServerIp":"","Mode":"socks5","Status":true,"RunStatus":false,"Client":{"Cnf":{"U":"","P":"","Compress":false,"Crypt":false},"Id":2,"VerifyKey":"m3ue28maxy3pgqp8","Addr":"","Remark":"","Status":true,"IsConnect":false,"RateLimit":0,"Flow":{"ExportFlow":0,"InletFlow":0,"FlowLimit":0},"Rate":{"NowRate":0},"NoStore":false,"NoDisplay":false,"MaxConn":0,"NowConn":0,"WebUserName":"","WebPassword":"","ConfigConnAllow":true,"MaxTunnelNum":0},"Ports":"","Flow":{"ExportFlow":0,"InletFlow":0,"FlowLimit":0},"Password":"","Remark":"","TargetAddr":"","NoStore":false,"LocalPath":"","StripPre":"","Target":{"TargetStr":"","TargetArr":null,"LocalProxy":false},"HealthCheckTimeout":0,"HealthMaxFail":0,"HealthCheckInterval":0,"HealthNextTime":"0001-01-01T00:00:00Z","HealthMap":null,"HttpHealthUrl":"","HealthRemoveArr":null,"HealthCheckType":"","HealthCheckTarget":""}
+*#*

+ 34 - 0
core/struct.go

@@ -0,0 +1,34 @@
+package core
+
+import (
+	"context"
+)
+
+// This structure is used to describe the plugin configuration item name and description.
+type Config struct {
+	ConfigName  string
+	Description string
+}
+
+type Stage uint8
+
+// These constants are meant to describe the stage in which the plugin is running.
+const (
+	STAGE_START_RUN_END Stage = iota
+	STAGE_START_RUN
+	STAGE_START_END
+	STAGE_RUN_END
+	STAGE_START
+	STAGE_END
+	STAGE_RUN
+)
+
+// Plugin interface, all plugins must implement those functions.
+type Plugin interface {
+	GetConfigName() []*Config
+	GetBeforePlugin() Plugin
+	GetStage() Stage
+	Start(ctx context.Context, config map[string]string) error
+	Run(ctx context.Context, config map[string]string) error
+	End(ctx context.Context, config map[string]string) error
+}

+ 36 - 0
module.md

@@ -0,0 +1,36 @@
+主干程序模块化编写
+
+假设socks5来说
+首先需要定一个一个socks5 struct {
+包含
+客户端地址
+服务端地址
+读到的用户名
+读到的密码
+连接类型(tcp、udp)
+远程地址(ipv4 ipv6)
+远程端口
+}
+
+每个模块需要一个获取配置参数的func
+
+定义好了之后在每每个模块中对该结=结构体进行操作
+
+调用每一个模块的时候,需要如下参数
+ctx上线文
+socks5结构体
+该module的配置
+当前的connection
+预分配的connection
+每个模块根据自己的业务逻辑进行处理
+
+
+其他技术:
+零拷贝
+事件驱动
+回调
+触发器
+
+
+插件启动范围
+插件优先级

+ 1 - 0
server/proxy/socks5.go

@@ -199,6 +199,7 @@ func (s *Sock5ModeServer) handleConn(c net.Conn) {
 		c.Close()
 		return
 	}
+
 	if s.task.Client.Cnf.U != "" && s.task.Client.Cnf.P != "" {
 		buf[1] = UserPassAuth
 		c.Write(buf)

+ 128 - 0
server/socks5/socks5_access_handle.go

@@ -0,0 +1,128 @@
+package socks5
+
+import (
+	"context"
+	"errors"
+	"github.com/cnlh/nps/core"
+	"io"
+	"net"
+)
+
+const (
+	UserPassAuth    = uint8(2)
+	userAuthVersion = uint8(1)
+	authSuccess     = uint8(0)
+	authFailure     = uint8(1)
+	UserNoAuth      = uint8(0)
+)
+
+type Access struct {
+	clientConn net.Conn
+	username   string
+	password   string
+}
+
+func (access *Access) GetConfigName() []*core.Config {
+	c := make([]*core.Config, 0)
+	c = append(c, &core.Config{ConfigName: "socks5_check_access", Description: "need check the permission?"})
+	c = append(c, &core.Config{ConfigName: "socks5_access_username", Description: "auth username"})
+	c = append(c, &core.Config{ConfigName: "socks5_access_password", Description: "auth password"})
+	return nil
+}
+
+func (access *Access) GetStage() core.Stage {
+	return core.STAGE_RUN
+}
+
+func (access *Access) GetBeforePlugin() core.Plugin {
+	return &Handshake{}
+}
+
+func (access *Access) Start(ctx context.Context, config map[string]string) error {
+	return nil
+}
+func (access *Access) End(ctx context.Context, config map[string]string) error {
+	return nil
+}
+
+func (access *Access) Run(ctx context.Context, config map[string]string) error {
+	clientCtxConn := ctx.Value("clientConn")
+	if clientCtxConn == nil {
+		return errors.New("the client access.clientConnection is not exist")
+	}
+	access.clientConn = clientCtxConn.(net.Conn)
+	if config["socks5_check_access"] != "true" {
+		return access.sendAccessMsgToClient(UserNoAuth)
+	}
+	configUsername := config["socks5_access_username"]
+	configPassword := config["socks5_access_password"]
+	if configUsername == "" || configPassword == "" {
+		return access.sendAccessMsgToClient(UserNoAuth)
+	}
+	// need auth
+	if err := access.sendAccessMsgToClient(UserPassAuth); err != nil {
+		return err
+	}
+	// send auth reply to client ,and get the auth information
+	var err error
+	access.username, access.password, err = access.getAuthInfoFromClient()
+	if err != nil {
+		return err
+	}
+	context.WithValue(ctx, access.username, access.password)
+	// check
+	return access.checkAuth(configUsername, configPassword)
+}
+
+func (access *Access) sendAccessMsgToClient(auth uint8) error {
+	buf := make([]byte, 2)
+	buf[0] = 5
+	buf[1] = auth
+	n, err := access.clientConn.Write(buf)
+	if err != nil || n != 2 {
+		return errors.New("write access message to client error " + err.Error())
+	}
+	return nil
+}
+
+func (access *Access) getAuthInfoFromClient() (username string, password string, err error) {
+	header := []byte{0, 0}
+	if _, err = io.ReadAtLeast(access.clientConn, header, 2); err != nil {
+		return
+	}
+	if header[0] != userAuthVersion {
+		err = errors.New("authentication method is not supported")
+		return
+	}
+	userLen := int(header[1])
+	user := make([]byte, userLen)
+	if _, err = io.ReadAtLeast(access.clientConn, user, userLen); err != nil {
+		return
+	}
+	if _, err := access.clientConn.Read(header[:1]); err != nil {
+		err = errors.New("get password length error" + err.Error())
+		return
+	}
+	passLen := int(header[0])
+	pass := make([]byte, passLen)
+	if _, err := io.ReadAtLeast(access.clientConn, pass, passLen); err != nil {
+		err = errors.New("get password error" + err.Error())
+		return
+	}
+	username = string(user)
+	password = string(pass)
+	return
+}
+
+func (access *Access) checkAuth(configUserName, configPassword string) error {
+	if access.username == configUserName && access.password == configPassword {
+		_, err := access.clientConn.Write([]byte{userAuthVersion, authSuccess})
+		return err
+	} else {
+		_, err := access.clientConn.Write([]byte{userAuthVersion, authFailure})
+		if err != nil {
+			return err
+		}
+		return errors.New("auth check error,username or password does not match")
+	}
+}

+ 58 - 0
server/socks5/socks5_handshake_handle.go

@@ -0,0 +1,58 @@
+package socks5
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"github.com/cnlh/nps/core"
+	"io"
+	"net"
+)
+
+type Handshake struct {
+}
+
+func (handshake *Handshake) GetConfigName() []*core.Config {
+	return nil
+}
+func (handshake *Handshake) GetStage() core.Stage {
+	return core.STAGE_RUN
+}
+func (handshake *Handshake) GetBeforePlugin() core.Plugin {
+	return nil
+}
+func (handshake *Handshake) Start(ctx context.Context, config map[string]string) error {
+	return nil
+}
+
+func (handshake *Handshake) Run(ctx context.Context, config map[string]string) error {
+	clientCtxConn := ctx.Value("clientConn")
+	if clientCtxConn == nil {
+		return errors.New("the client connection is not exist")
+	}
+	clientConn := clientCtxConn.(net.Conn)
+
+	buf := make([]byte, 2)
+	if _, err := io.ReadFull(clientConn, buf); err != nil {
+		return errors.New("negotiation err while read 2 bytes from client connection: " + err.Error())
+	}
+
+	if version := buf[0]; version != 5 {
+		return errors.New("only support socks5")
+	}
+	nMethods := buf[1]
+
+	methods := make([]byte, nMethods)
+
+	if n, err := clientConn.Read(methods); n != int(nMethods) || err != nil {
+		return errors.New(fmt.Sprintf("read methods error, need %d , read  %d, error %s", nMethods, n, err.Error()))
+	} else {
+		context.WithValue(ctx, "methods", methods[:n])
+	}
+
+	return nil
+}
+
+func (handshake *Handshake) End(ctx context.Context, config map[string]string) error {
+	return nil
+}