This commit is contained in:
unknown 2019-10-15 17:12:27 +08:00
parent f4ae503982
commit 6771816be7
8 changed files with 153 additions and 86 deletions

75
core/plugin.go Normal file
View File

@ -0,0 +1,75 @@
package core
import (
"context"
"github.com/cnlh/nps/bridge"
"net"
)
// Plugin interface, all plugins must implement those functions.
type Plugin interface {
GetConfigName() *NpsConfigs
GetConfigLevel() ConfigLevel
GetStage() Stage
Start(ctx context.Context, config map[string]string) (context.Context, error)
Run(ctx context.Context, config map[string]string) (context.Context, error)
End(ctx context.Context, config map[string]string) (context.Context, error)
}
type NpsPlugin struct {
Version string
}
func (npsPlugin *NpsPlugin) GetConfigName() *NpsConfigs {
return nil
}
// describe the config level
func (npsPlugin *NpsPlugin) GetConfigLevel() ConfigLevel {
return CONFIG_LEVEL_PLUGIN
}
// describe the stage of the plugin
func (npsPlugin *NpsPlugin) GetStage() Stage {
return STAGE_RUN
}
func (npsPlugin *NpsPlugin) Start(ctx context.Context, config map[string]string) (context.Context, error) {
return ctx, nil
}
func (npsPlugin *NpsPlugin) Run(ctx context.Context, config map[string]string) (context.Context, error) {
return ctx, nil
}
func (npsPlugin *NpsPlugin) End(ctx context.Context, config map[string]string) (context.Context, error) {
return ctx, nil
}
func (npsPlugin *NpsPlugin) GetClientConn(ctx context.Context) net.Conn {
return ctx.Value(CLIENT_CONNECTION).(net.Conn)
}
func (npsPlugin *NpsPlugin) GetBridge(ctx context.Context) *bridge.Bridge {
return ctx.Value(BRIDGE).(*bridge.Bridge)
}
func (npsPlugin *NpsPlugin) GetClientId(ctx context.Context) int {
return ctx.Value(CLIENT_ID).(int)
}
type Plugins struct {
pgs []Plugin
}
func NewPlugins() *Plugins {
p := &Plugins{}
p.pgs = make([]Plugin, 0)
return p
}
func (pl *Plugins) Add(plugins ...Plugin) {
for _, plugin := range plugins {
pl.pgs = append(pl.pgs, plugin)
}
}

View File

@ -1,10 +1,7 @@
package core package core
import ( import (
"context"
"errors" "errors"
"github.com/cnlh/nps/bridge"
"net"
) )
type Stage uint8 type Stage uint8
@ -26,53 +23,18 @@ const (
CLIENT_ID = "client_id" CLIENT_ID = "client_id"
) )
type ConfigLevel uint8
const (
CONFIG_LEVEL_CLIENT ConfigLevel = iota
CONFIG_LEVEL_PLUGIN
CONFIG_LEVEL_GLOBAL
)
var ( var (
CLIENT_CONNECTION_NOT_EXIST = errors.New("the client connection is not exist") CLIENT_CONNECTION_NOT_EXIST = errors.New("the client connection is not exist")
BRIDGE_NOT_EXIST = errors.New("the client connection is not exist") BRIDGE_NOT_EXIST = errors.New("the client connection is not exist")
REQUEST_EOF = errors.New("the request has finished") REQUEST_EOF = errors.New("the request has finished")
CLIENT_ID_NOT_EXIST = errors.New("the request has finished") CLIENT_ID_NOT_EXIST = errors.New("the client id is not exist")
) )
// Plugin interface, all plugins must implement those functions.
type Plugin interface {
GetConfigName() *NpsConfigs
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
}
type NpsPlugin struct {
}
func (npsPlugin *NpsPlugin) GetConfigName() *NpsConfigs {
return nil
}
func (npsPlugin *NpsPlugin) GetStage() Stage {
return STAGE_RUN
}
func (npsPlugin *NpsPlugin) Start(ctx context.Context, config map[string]string) error {
return nil
}
func (npsPlugin *NpsPlugin) Run(ctx context.Context, config map[string]string) error {
return nil
}
func (npsPlugin *NpsPlugin) End(ctx context.Context, config map[string]string) error {
return nil
}
func (npsPlugin *NpsPlugin) GetClientConn(ctx context.Context) net.Conn {
return ctx.Value(CLIENT_CONNECTION).(net.Conn)
}
func (npsPlugin *NpsPlugin) GetBridge(ctx context.Context) *bridge.Bridge {
return ctx.Value(BRIDGE).(*bridge.Bridge)
}
func (npsPlugin *NpsPlugin) GetClientId(ctx context.Context) int {
return ctx.Value(CLIENT_ID).(int)
}

View File

@ -16,24 +16,18 @@ func (proxy *Proxy) GetConfigName() *core.NpsConfigs {
return core.NewNpsConfigs("socks5_proxy", "proxy to inet") return core.NewNpsConfigs("socks5_proxy", "proxy to inet")
} }
func (proxy *Proxy) Run(ctx context.Context, config map[string]string) error { func (proxy *Proxy) Run(ctx context.Context, config map[string]string) (context.Context, error) {
proxy.clientConn = proxy.GetClientConn(ctx)
proxy.ctx = ctx proxy.ctx = ctx
proxy.clientConn = proxy.GetClientConn(ctx)
clientCtxConn := ctx.Value(core.CLIENT_CONNECTION)
if clientCtxConn == nil {
return core.CLIENT_CONNECTION_NOT_EXIST
}
clientId := proxy.GetClientId(ctx) clientId := proxy.GetClientId(ctx)
brg := proxy.GetBridge(ctx) brg := proxy.GetBridge(ctx)
severConn, err := brg.GetConnByClientId(clientId) severConn, err := brg.GetConnByClientId(clientId)
if err != nil { if err != nil {
return err return ctx, err
} }
go core.CopyBuffer(severConn, clientCtxConn.(net.Conn)) go core.CopyBuffer(severConn, proxy.clientConn)
core.CopyBuffer(clientCtxConn.(net.Conn), severConn) core.CopyBuffer(proxy.clientConn, severConn)
return nil return ctx, nil
} }

View File

@ -23,12 +23,12 @@ func (check *CheckAccess) GetConfigName() *core.NpsConfigs {
return c return c
} }
func (check *CheckAccess) Run(ctx context.Context, config map[string]string) error { func (check *CheckAccess) Run(ctx context.Context, config map[string]string) (context.Context, error) {
check.clientConn = check.GetClientConn(ctx) check.clientConn = check.GetClientConn(ctx)
check.configUsername = config["socks5_access_username"] check.configUsername = config["socks5_access_username"]
check.configPassword = config["socks5_access_password"] check.configPassword = config["socks5_access_password"]
return nil return ctx, nil
} }
func (check *CheckAccess) checkAuth(configUserName, configPassword string) error { func (check *CheckAccess) checkAuth(configUserName, configPassword string) error {

View File

@ -12,25 +12,25 @@ type Handshake struct {
core.NpsPlugin core.NpsPlugin
} }
func (handshake *Handshake) Run(ctx context.Context, config map[string]string) error { func (handshake *Handshake) Run(ctx context.Context, config map[string]string) (context.Context, error) {
clientConn := handshake.GetClientConn(ctx) clientConn := handshake.GetClientConn(ctx)
buf := make([]byte, 2) buf := make([]byte, 2)
if _, err := io.ReadFull(clientConn, buf); err != nil { if _, err := io.ReadFull(clientConn, buf); err != nil {
return errors.New("negotiation err while read 2 bytes from client connection: " + err.Error()) return ctx, errors.New("negotiation err while read 2 bytes from client connection: " + err.Error())
} }
if version := buf[0]; version != 5 { if version := buf[0]; version != 5 {
return errors.New("only support socks5") return ctx, errors.New("only support socks5")
} }
nMethods := buf[1] nMethods := buf[1]
methods := make([]byte, nMethods) methods := make([]byte, nMethods)
if n, err := clientConn.Read(methods); n != int(nMethods) || err != nil { 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())) return ctx, errors.New(fmt.Sprintf("read methods error, need %d , read %d, error %s", nMethods, n, err.Error()))
} else { } else {
context.WithValue(ctx, "methods", methods[:n]) ctx = context.WithValue(ctx, "methods", methods[:n])
} }
return nil return ctx, nil
} }

View File

@ -25,24 +25,24 @@ func (access *Access) GetConfigName() *core.NpsConfigs {
return core.NewNpsConfigs("socks5_check_access_check", "need check the permission simply") return core.NewNpsConfigs("socks5_check_access_check", "need check the permission simply")
} }
func (access *Access) Run(ctx context.Context, config map[string]string) error { func (access *Access) Run(ctx context.Context, config map[string]string) (context.Context, error) {
access.clientConn = access.GetClientConn(ctx) access.clientConn = access.GetClientConn(ctx)
if config["socks5_check_access"] != "true" { if config["socks5_check_access"] != "true" {
return access.sendAccessMsgToClient(UserNoAuth) return ctx, access.sendAccessMsgToClient(UserNoAuth)
} }
// need auth // need auth
if err := access.sendAccessMsgToClient(UserPassAuth); err != nil { if err := access.sendAccessMsgToClient(UserPassAuth); err != nil {
return err return ctx, err
} }
// send auth reply to client ,and get the auth information // send auth reply to client ,and get the auth information
username, password, err := access.getAuthInfoFromClient() username, password, err := access.getAuthInfoFromClient()
if err != nil { if err != nil {
return err return ctx, err
} }
context.WithValue(ctx, "socks_client_username", username) ctx = context.WithValue(ctx, "socks_client_username", username)
context.WithValue(ctx, "socks_client_password", password) ctx = context.WithValue(ctx, "socks_client_password", password)
// check // check
return nil return ctx, nil
} }
func (access *Access) sendAccessMsgToClient(auth uint8) error { func (access *Access) sendAccessMsgToClient(auth uint8) error {

View File

@ -32,7 +32,7 @@ const (
addrTypeNotSupported = 8 addrTypeNotSupported = 8
) )
func (request *Request) Run(ctx context.Context, config map[string]string) error { func (request *Request) Run(ctx context.Context, config map[string]string) (context.Context, error) {
request.clientConn = request.GetClientConn(ctx) request.clientConn = request.GetClientConn(ctx)
request.ctx = ctx request.ctx = ctx
@ -49,23 +49,23 @@ func (request *Request) Run(ctx context.Context, config map[string]string) error
_, err := io.ReadFull(request.clientConn, header) _, err := io.ReadFull(request.clientConn, header)
if err != nil { if err != nil {
return errors.New("illegal request" + err.Error()) return request.ctx, errors.New("illegal request" + err.Error())
} }
switch header[1] { switch header[1] {
case connectMethod: case connectMethod:
context.WithValue(request.ctx, core.PROXY_CONNECTION_TYPE, "tcp") request.ctx = context.WithValue(request.ctx, core.PROXY_CONNECTION_TYPE, "tcp")
return request.doConnect() return request.ctx, request.doConnect()
case bindMethod: case bindMethod:
return request.handleBind() return request.ctx, request.handleBind()
case associateMethod: case associateMethod:
context.WithValue(request.ctx, core.PROXY_CONNECTION_TYPE, "udp") request.ctx = context.WithValue(request.ctx, core.PROXY_CONNECTION_TYPE, "udp")
return request.handleUDP() return request.ctx, request.handleUDP()
default: default:
request.sendReply(commandNotSupported) request.sendReply(commandNotSupported)
return errors.New("command not supported") return request.ctx, errors.New("command not supported")
} }
return nil return request.ctx, nil
} }
func (request *Request) sendReply(rep uint8) error { func (request *Request) sendReply(rep uint8) error {
@ -116,8 +116,8 @@ func (request *Request) doConnect() error {
var port uint16 var port uint16
binary.Read(request.clientConn, binary.BigEndian, &port) binary.Read(request.clientConn, binary.BigEndian, &port)
context.WithValue(request.ctx, core.PROXY_CONNECTION_ADDR, host) request.ctx = context.WithValue(request.ctx, core.PROXY_CONNECTION_ADDR, host)
context.WithValue(request.ctx, core.PROXY_CONNECTION_PORT, port) request.ctx = context.WithValue(request.ctx, core.PROXY_CONNECTION_PORT, port)
return nil return nil
} }

View File

@ -0,0 +1,36 @@
package socks5
import (
"github.com/cnlh/nps/core"
"github.com/cnlh/nps/lib/conn"
"github.com/cnlh/nps/server/common"
"net"
"strconv"
)
type S5Server struct {
globalConfig map[string]string
clientConfig map[string]string
pluginConfig map[string]string
ServerIp string
ServerPort int
plugins *core.Plugins
listener net.Listener
}
func NewS5Server(globalConfig, clientConfig, pluginConfig map[string]string) *S5Server {
s5 := &S5Server{
globalConfig: globalConfig,
clientConfig: clientConfig,
pluginConfig: pluginConfig,
plugins: &core.Plugins{},
}
s5.plugins.Add(new(Handshake), new(Access), new(CheckAccess), new(Request), new(common.Proxy))
return s5
}
func (s5 *S5Server) Start() error {
return conn.NewTcpListenerAndProcess(s5.ServerIp+":"+strconv.Itoa(s5.ServerPort), func(c net.Conn) {
}, &s5.listener)
}