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
import (
"context"
"errors"
"github.com/cnlh/nps/bridge"
"net"
)
type Stage uint8
@ -26,53 +23,18 @@ const (
CLIENT_ID = "client_id"
)
type ConfigLevel uint8
const (
CONFIG_LEVEL_CLIENT ConfigLevel = iota
CONFIG_LEVEL_PLUGIN
CONFIG_LEVEL_GLOBAL
)
var (
CLIENT_CONNECTION_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")
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")
}
func (proxy *Proxy) Run(ctx context.Context, config map[string]string) error {
proxy.clientConn = proxy.GetClientConn(ctx)
func (proxy *Proxy) Run(ctx context.Context, config map[string]string) (context.Context, error) {
proxy.ctx = ctx
clientCtxConn := ctx.Value(core.CLIENT_CONNECTION)
if clientCtxConn == nil {
return core.CLIENT_CONNECTION_NOT_EXIST
}
proxy.clientConn = proxy.GetClientConn(ctx)
clientId := proxy.GetClientId(ctx)
brg := proxy.GetBridge(ctx)
severConn, err := brg.GetConnByClientId(clientId)
if err != nil {
return err
return ctx, err
}
go core.CopyBuffer(severConn, clientCtxConn.(net.Conn))
core.CopyBuffer(clientCtxConn.(net.Conn), severConn)
return nil
go core.CopyBuffer(severConn, proxy.clientConn)
core.CopyBuffer(proxy.clientConn, severConn)
return ctx, nil
}

View File

@ -23,12 +23,12 @@ func (check *CheckAccess) GetConfigName() *core.NpsConfigs {
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.configUsername = config["socks5_access_username"]
check.configPassword = config["socks5_access_password"]
return nil
return ctx, nil
}
func (check *CheckAccess) checkAuth(configUserName, configPassword string) error {

View File

@ -12,25 +12,25 @@ type Handshake struct {
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)
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())
return ctx, 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")
return ctx, 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()))
return ctx, errors.New(fmt.Sprintf("read methods error, need %d , read %d, error %s", nMethods, n, err.Error()))
} 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")
}
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)
if config["socks5_check_access"] != "true" {
return access.sendAccessMsgToClient(UserNoAuth)
return ctx, access.sendAccessMsgToClient(UserNoAuth)
}
// need auth
if err := access.sendAccessMsgToClient(UserPassAuth); err != nil {
return err
return ctx, err
}
// send auth reply to client ,and get the auth information
username, password, err := access.getAuthInfoFromClient()
if err != nil {
return err
return ctx, err
}
context.WithValue(ctx, "socks_client_username", username)
context.WithValue(ctx, "socks_client_password", password)
ctx = context.WithValue(ctx, "socks_client_username", username)
ctx = context.WithValue(ctx, "socks_client_password", password)
// check
return nil
return ctx, nil
}
func (access *Access) sendAccessMsgToClient(auth uint8) error {

View File

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