mirror of
https://github.com/ehang-io/nps.git
synced 2025-07-03 04:53:50 +00:00
module
This commit is contained in:
parent
5e5df224b7
commit
b6a9001d43
50
core/const.go
Normal file
50
core/const.go
Normal file
@ -0,0 +1,50 @@
|
||||
package core
|
||||
|
||||
const (
|
||||
CONN_DATA_SEQ = "*#*" //Separator
|
||||
VERIFY_EER = "vkey"
|
||||
VERIFY_SUCCESS = "sucs"
|
||||
WORK_MAIN = "main"
|
||||
WORK_CHAN = "chan"
|
||||
WORK_CONFIG = "conf"
|
||||
WORK_REGISTER = "rgst"
|
||||
WORK_SECRET = "sert"
|
||||
WORK_FILE = "file"
|
||||
WORK_P2P = "p2pm"
|
||||
WORK_P2P_VISITOR = "p2pv"
|
||||
WORK_P2P_PROVIDER = "p2pp"
|
||||
WORK_P2P_CONNECT = "p2pc"
|
||||
WORK_P2P_SUCCESS = "p2ps"
|
||||
WORK_P2P_END = "p2pe"
|
||||
WORK_P2P_LAST = "p2pl"
|
||||
WORK_STATUS = "stus"
|
||||
RES_MSG = "msg0"
|
||||
RES_CLOSE = "clse"
|
||||
NEW_UDP_CONN = "udpc" //p2p udp conn
|
||||
NEW_TASK = "task"
|
||||
NEW_CONF = "conf"
|
||||
NEW_HOST = "host"
|
||||
CONN_TCP = "tcp"
|
||||
CONN_UDP = "udp"
|
||||
CONN_TEST = "TST"
|
||||
UnauthorizedBytes = `HTTP/1.1 401 Unauthorized
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
WWW-Authenticate: Basic realm="easyProxy"
|
||||
|
||||
401 Unauthorized`
|
||||
ConnectionFailBytes = `HTTP/1.1 404 Not Found
|
||||
|
||||
`
|
||||
)
|
||||
|
||||
const (
|
||||
MUX_PING_FLAG uint8 = iota
|
||||
MUX_NEW_CONN_OK
|
||||
MUX_NEW_CONN_Fail
|
||||
MUX_NEW_MSG
|
||||
MUX_MSG_SEND_OK
|
||||
MUX_NEW_CONN
|
||||
MUX_CONN_CLOSE
|
||||
MUX_PING_RETURN
|
||||
MUX_PING int32 = -1
|
||||
)
|
209
core/netpackager.go
Normal file
209
core/netpackager.go
Normal file
@ -0,0 +1,209 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type NetPackager interface {
|
||||
Pack(writer io.Writer) (err error)
|
||||
UnPack(reader io.Reader) (err error)
|
||||
}
|
||||
|
||||
type BasePackager struct {
|
||||
Length uint32
|
||||
Content []byte
|
||||
}
|
||||
|
||||
func (Self *BasePackager) NewPac(contents ...interface{}) (err error) {
|
||||
Self.clean()
|
||||
for _, content := range contents {
|
||||
switch content.(type) {
|
||||
case nil:
|
||||
Self.Content = Self.Content[:0]
|
||||
case []byte:
|
||||
err = Self.appendByte(content.([]byte))
|
||||
case string:
|
||||
err = Self.appendByte([]byte(content.(string)))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = Self.appendByte([]byte(CONN_DATA_SEQ))
|
||||
default:
|
||||
err = Self.marshal(content)
|
||||
}
|
||||
}
|
||||
Self.setLength()
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *BasePackager) appendByte(data []byte) (err error) {
|
||||
m := len(Self.Content)
|
||||
n := m + len(data)
|
||||
if n <= cap(Self.Content) {
|
||||
Self.Content = Self.Content[0:n] // grow the length for copy
|
||||
copy(Self.Content[m:n], data)
|
||||
return nil
|
||||
} else {
|
||||
return errors.New("pack content too large")
|
||||
}
|
||||
}
|
||||
|
||||
//似乎这里涉及到父类作用域问题,当子类调用父类的方法时,其struct仅仅为父类的
|
||||
func (Self *BasePackager) Pack(writer io.Writer) (err error) {
|
||||
err = binary.Write(writer, binary.LittleEndian, Self.Length)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = binary.Write(writer, binary.LittleEndian, Self.Content)
|
||||
return
|
||||
}
|
||||
|
||||
//Unpack 会导致传入的数字类型转化成float64!!
|
||||
//主要原因是json unmarshal并未传入正确的数据类型
|
||||
func (Self *BasePackager) UnPack(reader io.Reader) (err error) {
|
||||
Self.clean()
|
||||
err = binary.Read(reader, binary.LittleEndian, &Self.Length)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if int(Self.Length) > cap(Self.Content) {
|
||||
err = errors.New("unpack err, content length too large")
|
||||
}
|
||||
Self.Content = Self.Content[:int(Self.Length)]
|
||||
//n, err := io.ReadFull(reader, Self.Content)
|
||||
//if n != int(Self.Length) {
|
||||
// err = io.ErrUnexpectedEOF
|
||||
//}
|
||||
err = binary.Read(reader, binary.LittleEndian, Self.Content)
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *BasePackager) marshal(content interface{}) (err error) {
|
||||
tmp, err := json.Marshal(content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = Self.appendByte(tmp)
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *BasePackager) Unmarshal(content interface{}) (err error) {
|
||||
err = json.Unmarshal(Self.Content, content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *BasePackager) setLength() {
|
||||
Self.Length = uint32(len(Self.Content))
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *BasePackager) clean() {
|
||||
Self.Length = 0
|
||||
Self.Content = Self.Content[:0] // reset length
|
||||
}
|
||||
|
||||
func (Self *BasePackager) Split() (strList []string) {
|
||||
n := bytes.IndexByte(Self.Content, 0)
|
||||
strList = strings.Split(string(Self.Content[:n]), CONN_DATA_SEQ)
|
||||
strList = strList[0 : len(strList)-1]
|
||||
return
|
||||
}
|
||||
|
||||
type ConnPackager struct { // Todo
|
||||
ConnType uint8
|
||||
BasePackager
|
||||
}
|
||||
|
||||
func (Self *ConnPackager) NewPac(connType uint8, content ...interface{}) (err error) {
|
||||
Self.ConnType = connType
|
||||
err = Self.BasePackager.NewPac(content...)
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *ConnPackager) Pack(writer io.Writer) (err error) {
|
||||
err = binary.Write(writer, binary.LittleEndian, Self.ConnType)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = Self.BasePackager.Pack(writer)
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *ConnPackager) UnPack(reader io.Reader) (err error) {
|
||||
err = binary.Read(reader, binary.LittleEndian, &Self.ConnType)
|
||||
if err != nil && err != io.EOF {
|
||||
return
|
||||
}
|
||||
err = Self.BasePackager.UnPack(reader)
|
||||
return
|
||||
}
|
||||
|
||||
type MuxPackager struct {
|
||||
Flag uint8
|
||||
Id int32
|
||||
Window uint16
|
||||
BasePackager
|
||||
}
|
||||
|
||||
func (Self *MuxPackager) NewPac(flag uint8, id int32, content ...interface{}) (err error) {
|
||||
Self.Flag = flag
|
||||
Self.Id = id
|
||||
if flag == MUX_NEW_MSG {
|
||||
err = Self.BasePackager.NewPac(content...)
|
||||
}
|
||||
if flag == MUX_MSG_SEND_OK {
|
||||
// MUX_MSG_SEND_OK only allows one data
|
||||
switch content[0].(type) {
|
||||
case int:
|
||||
Self.Window = uint16(content[0].(int))
|
||||
case uint16:
|
||||
Self.Window = content[0].(uint16)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *MuxPackager) Pack(writer io.Writer) (err error) {
|
||||
err = binary.Write(writer, binary.LittleEndian, Self.Flag)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = binary.Write(writer, binary.LittleEndian, Self.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if Self.Flag == MUX_NEW_MSG {
|
||||
err = Self.BasePackager.Pack(writer)
|
||||
}
|
||||
if Self.Flag == MUX_MSG_SEND_OK {
|
||||
err = binary.Write(writer, binary.LittleEndian, Self.Window)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *MuxPackager) UnPack(reader io.Reader) (err error) {
|
||||
Self.BasePackager.clean() // also clean the content
|
||||
err = binary.Read(reader, binary.LittleEndian, &Self.Flag)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = binary.Read(reader, binary.LittleEndian, &Self.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if Self.Flag == MUX_NEW_MSG {
|
||||
err = Self.BasePackager.UnPack(reader)
|
||||
}
|
||||
if Self.Flag == MUX_MSG_SEND_OK {
|
||||
err = binary.Read(reader, binary.LittleEndian, &Self.Window)
|
||||
}
|
||||
return
|
||||
}
|
@ -9,7 +9,7 @@ import (
|
||||
// Plugin interface, all plugins must implement those functions.
|
||||
type Plugin interface {
|
||||
GetConfigName() *NpsConfigs
|
||||
InitConfig(globalConfig, clientConfig, pluginConfig map[string]string)
|
||||
InitConfig(globalConfig, clientConfig, pluginConfig map[string]string, pgCnf []*Config)
|
||||
GetStage() []Stage
|
||||
Start(ctx context.Context) (context.Context, error)
|
||||
Run(ctx context.Context) (context.Context, error)
|
||||
@ -25,9 +25,9 @@ func (npsPlugin *NpsPlugin) GetConfigName() *NpsConfigs {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (npsPlugin *NpsPlugin) InitConfig(globalConfig, clientConfig, pluginConfig map[string]string) {
|
||||
func (npsPlugin *NpsPlugin) InitConfig(globalConfig, clientConfig, pluginConfig map[string]string, pgCnf []*Config) {
|
||||
npsPlugin.Configs = make(map[string]string)
|
||||
for _, cfg := range npsPlugin.GetConfigName().GetAll() {
|
||||
for _, cfg := range pgCnf {
|
||||
switch cfg.ConfigLevel {
|
||||
case CONFIG_LEVEL_PLUGIN:
|
||||
npsPlugin.Configs[cfg.ConfigName] = pluginConfig[cfg.ConfigName]
|
||||
@ -105,13 +105,20 @@ func (pl *Plugins) Add(plugins ...Plugin) {
|
||||
}
|
||||
}
|
||||
|
||||
func RunPlugin(ctx context.Context, pgs []Plugin) error {
|
||||
func RunPlugin(ctx context.Context, pgs []Plugin, stage Stage) (context.Context, error) {
|
||||
var err error
|
||||
for _, pg := range pgs {
|
||||
ctx, err = pg.Start(ctx)
|
||||
switch stage {
|
||||
case STAGE_RUN:
|
||||
ctx, err = pg.Run(ctx)
|
||||
case STAGE_START:
|
||||
ctx, err = pg.Start(ctx)
|
||||
case STAGE_END:
|
||||
ctx, err = pg.End(ctx)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
return ctx, err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return ctx, nil
|
||||
}
|
||||
|
@ -2,14 +2,14 @@ package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/cnlh/nps/core"
|
||||
"net"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Proxy struct {
|
||||
core.NpsPlugin
|
||||
clientConn net.Conn
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func (proxy *Proxy) GetConfigName() *core.NpsConfigs {
|
||||
@ -17,10 +17,9 @@ func (proxy *Proxy) GetConfigName() *core.NpsConfigs {
|
||||
}
|
||||
|
||||
func (proxy *Proxy) Run(ctx context.Context) (context.Context, error) {
|
||||
proxy.ctx = ctx
|
||||
proxy.clientConn = proxy.GetClientConn(ctx)
|
||||
clientId := proxy.GetClientId(ctx)
|
||||
brg := proxy.GetBridge(ctx)
|
||||
clientConn := proxy.GetClientConn(ctx)
|
||||
//clientId := proxy.GetClientId(ctx)
|
||||
//brg := proxy.GetBridge(ctx)
|
||||
|
||||
//severConn, err := brg.GetConnByClientId(clientId)
|
||||
//if err != nil {
|
||||
@ -31,12 +30,22 @@ func (proxy *Proxy) Run(ctx context.Context) (context.Context, error) {
|
||||
//if _, err := core.SendInfo(severConn, nil); err != nil {
|
||||
// return ctx, err
|
||||
//}
|
||||
severConn, err := net.Dial(ctx.Value(core.PROXY_CONNECTION_TYPE).(string), ctx.Value(core.PROXY_CONNECTION_ADDR).(string)+":"+ctx.Value(core.PROXY_CONNECTION_PORT).(string))
|
||||
connType := ctx.Value(core.PROXY_CONNECTION_TYPE).(string)
|
||||
connAddr := ctx.Value(core.PROXY_CONNECTION_ADDR).(string)
|
||||
connPort := strconv.Itoa(int(ctx.Value(core.PROXY_CONNECTION_PORT).(uint16)))
|
||||
fmt.Println(connType, connAddr, connPort, clientConn.RemoteAddr().String())
|
||||
serverConn, err := net.Dial(connType, connAddr+":"+connPort)
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
// data exchange
|
||||
go core.CopyBuffer(severConn, proxy.clientConn)
|
||||
core.CopyBuffer(proxy.clientConn, severConn)
|
||||
go func() {
|
||||
core.CopyBuffer(serverConn, clientConn)
|
||||
serverConn.Close()
|
||||
clientConn.Close()
|
||||
}()
|
||||
core.CopyBuffer(clientConn, serverConn)
|
||||
serverConn.Close()
|
||||
clientConn.Close()
|
||||
return ctx, core.REQUEST_EOF
|
||||
}
|
||||
|
@ -3,15 +3,13 @@ package socks5
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/cnlh/nps/core"
|
||||
"net"
|
||||
)
|
||||
|
||||
type CheckAccess struct {
|
||||
core.NpsPlugin
|
||||
clientConn net.Conn
|
||||
clientUsername string
|
||||
clientPassword string
|
||||
configUsername string
|
||||
configPassword string
|
||||
}
|
||||
@ -24,19 +22,23 @@ func (check *CheckAccess) GetConfigName() *core.NpsConfigs {
|
||||
}
|
||||
|
||||
func (check *CheckAccess) Run(ctx context.Context) (context.Context, error) {
|
||||
check.clientConn = check.GetClientConn(ctx)
|
||||
check.configUsername = check.Configs["socks5_access_username"]
|
||||
check.configPassword = check.Configs["socks5_access_password"]
|
||||
|
||||
clientConn := check.GetClientConn(ctx)
|
||||
check.configUsername = check.Configs["socks5_simple_access_username"]
|
||||
check.configPassword = check.Configs["socks5_simple_access_password"]
|
||||
if check.Configs["socks5_simple_access_check"] == "true" {
|
||||
connUsername := ctx.Value("socks_client_username").(string)
|
||||
connPassword := ctx.Value("socks_client_password").(string)
|
||||
return ctx, check.checkAuth(clientConn, connUsername, connPassword)
|
||||
}
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
func (check *CheckAccess) checkAuth(configUserName, configPassword string) error {
|
||||
if check.clientUsername == configUserName && check.clientPassword == configPassword {
|
||||
_, err := check.clientConn.Write([]byte{userAuthVersion, authSuccess})
|
||||
func (check *CheckAccess) checkAuth(clientConn net.Conn, connUserName, connPassword string) error {
|
||||
if check.configUsername == connUserName && check.configPassword == connPassword {
|
||||
_, err := clientConn.Write([]byte{userAuthVersion, authSuccess})
|
||||
return err
|
||||
} else {
|
||||
_, err := check.clientConn.Write([]byte{userAuthVersion, authFailure})
|
||||
_, err := clientConn.Write([]byte{userAuthVersion, authFailure})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -18,24 +18,23 @@ const (
|
||||
|
||||
type Access struct {
|
||||
core.NpsPlugin
|
||||
clientConn net.Conn
|
||||
}
|
||||
|
||||
func (access *Access) GetConfigName() *core.NpsConfigs {
|
||||
return core.NewNpsConfigs("socks5_check_access_check", "need check the permission simply",core.CONFIG_LEVEL_PLUGIN)
|
||||
return core.NewNpsConfigs("socks5_check_access", "need check the permission simply", core.CONFIG_LEVEL_PLUGIN)
|
||||
}
|
||||
|
||||
func (access *Access) Run(ctx context.Context) (context.Context, error) {
|
||||
access.clientConn = access.GetClientConn(ctx)
|
||||
clientConn := access.GetClientConn(ctx)
|
||||
if access.Configs["socks5_check_access"] != "true" {
|
||||
return ctx, access.sendAccessMsgToClient(UserNoAuth)
|
||||
return ctx, access.sendAccessMsgToClient(clientConn, UserNoAuth)
|
||||
}
|
||||
// need auth
|
||||
if err := access.sendAccessMsgToClient(UserPassAuth); err != nil {
|
||||
if err := access.sendAccessMsgToClient(clientConn, UserPassAuth); err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
// send auth reply to client ,and get the auth information
|
||||
username, password, err := access.getAuthInfoFromClient()
|
||||
username, password, err := access.getAuthInfoFromClient(clientConn)
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
@ -45,20 +44,20 @@ func (access *Access) Run(ctx context.Context) (context.Context, error) {
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
func (access *Access) sendAccessMsgToClient(auth uint8) error {
|
||||
func (access *Access) sendAccessMsgToClient(clientConn net.Conn, auth uint8) error {
|
||||
buf := make([]byte, 2)
|
||||
buf[0] = 5
|
||||
buf[1] = auth
|
||||
n, err := access.clientConn.Write(buf)
|
||||
n, err := 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) {
|
||||
func (access *Access) getAuthInfoFromClient(clientConn net.Conn) (username string, password string, err error) {
|
||||
header := []byte{0, 0}
|
||||
if _, err = io.ReadAtLeast(access.clientConn, header, 2); err != nil {
|
||||
if _, err = io.ReadAtLeast(clientConn, header, 2); err != nil {
|
||||
return
|
||||
}
|
||||
if header[0] != userAuthVersion {
|
||||
@ -67,16 +66,16 @@ func (access *Access) getAuthInfoFromClient() (username string, password string,
|
||||
}
|
||||
userLen := int(header[1])
|
||||
user := make([]byte, userLen)
|
||||
if _, err = io.ReadAtLeast(access.clientConn, user, userLen); err != nil {
|
||||
if _, err = io.ReadAtLeast(clientConn, user, userLen); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err := access.clientConn.Read(header[:1]); err != nil {
|
||||
if _, err = 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 {
|
||||
if _, err = io.ReadAtLeast(clientConn, pass, passLen); err != nil {
|
||||
err = errors.New("get password error" + err.Error())
|
||||
return
|
||||
}
|
||||
|
@ -12,8 +12,6 @@ import (
|
||||
|
||||
type Request struct {
|
||||
core.NpsPlugin
|
||||
clientConn net.Conn
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
const (
|
||||
@ -30,11 +28,11 @@ const (
|
||||
maxUDPPacketSize = 1476
|
||||
commandNotSupported = 7
|
||||
addrTypeNotSupported = 8
|
||||
succeeded = 0
|
||||
)
|
||||
|
||||
func (request *Request) Run(ctx context.Context) (context.Context, error) {
|
||||
request.clientConn = request.GetClientConn(ctx)
|
||||
request.ctx = ctx
|
||||
clientConn := request.GetClientConn(ctx)
|
||||
|
||||
/*
|
||||
The SOCKS request is formed as follows:
|
||||
@ -46,36 +44,36 @@ func (request *Request) Run(ctx context.Context) (context.Context, error) {
|
||||
*/
|
||||
header := make([]byte, 3)
|
||||
|
||||
_, err := io.ReadFull(request.clientConn, header)
|
||||
_, err := io.ReadFull(clientConn, header)
|
||||
|
||||
if err != nil {
|
||||
return request.ctx, errors.New("illegal request" + err.Error())
|
||||
return ctx, errors.New("illegal request" + err.Error())
|
||||
}
|
||||
|
||||
switch header[1] {
|
||||
case connectMethod:
|
||||
request.ctx = context.WithValue(request.ctx, core.PROXY_CONNECTION_TYPE, "tcp")
|
||||
return request.ctx, request.doConnect()
|
||||
ctx = context.WithValue(ctx, core.PROXY_CONNECTION_TYPE, "tcp")
|
||||
return request.doConnect(ctx, clientConn)
|
||||
case bindMethod:
|
||||
return request.ctx, request.handleBind()
|
||||
return ctx, request.handleBind()
|
||||
case associateMethod:
|
||||
request.ctx = context.WithValue(request.ctx, core.PROXY_CONNECTION_TYPE, "udp")
|
||||
return request.ctx, request.handleUDP()
|
||||
ctx = context.WithValue(ctx, core.PROXY_CONNECTION_TYPE, "udp")
|
||||
return request.handleUDP(ctx, clientConn)
|
||||
default:
|
||||
request.sendReply(commandNotSupported)
|
||||
return request.ctx, errors.New("command not supported")
|
||||
request.sendReply(clientConn, commandNotSupported)
|
||||
return ctx, errors.New("command not supported")
|
||||
}
|
||||
return request.ctx, nil
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
func (request *Request) sendReply(rep uint8) error {
|
||||
func (request *Request) sendReply(clientConn net.Conn, rep uint8) error {
|
||||
reply := []byte{
|
||||
5,
|
||||
rep,
|
||||
0,
|
||||
1,
|
||||
}
|
||||
localAddr := request.clientConn.LocalAddr().String()
|
||||
localAddr := clientConn.LocalAddr().String()
|
||||
localHost, localPort, _ := net.SplitHostPort(localAddr)
|
||||
ipBytes := net.ParseIP(localHost).To4()
|
||||
nPort, _ := strconv.Atoi(localPort)
|
||||
@ -83,42 +81,41 @@ func (request *Request) sendReply(rep uint8) error {
|
||||
portBytes := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(portBytes, uint16(nPort))
|
||||
reply = append(reply, portBytes...)
|
||||
_, err := request.clientConn.Write(reply)
|
||||
_, err := clientConn.Write(reply)
|
||||
return err
|
||||
}
|
||||
|
||||
//do conn
|
||||
func (request *Request) doConnect() error {
|
||||
func (request *Request) doConnect(ctx context.Context, clientConn net.Conn) (context.Context, error) {
|
||||
addrType := make([]byte, 1)
|
||||
request.clientConn.Read(addrType)
|
||||
clientConn.Read(addrType)
|
||||
|
||||
var host string
|
||||
switch addrType[0] {
|
||||
case ipV4:
|
||||
ipv4 := make(net.IP, net.IPv4len)
|
||||
request.clientConn.Read(ipv4)
|
||||
clientConn.Read(ipv4)
|
||||
host = ipv4.String()
|
||||
case ipV6:
|
||||
ipv6 := make(net.IP, net.IPv6len)
|
||||
request.clientConn.Read(ipv6)
|
||||
clientConn.Read(ipv6)
|
||||
host = ipv6.String()
|
||||
case domainName:
|
||||
var domainLen uint8
|
||||
binary.Read(request.clientConn, binary.BigEndian, &domainLen)
|
||||
binary.Read(clientConn, binary.BigEndian, &domainLen)
|
||||
domain := make([]byte, domainLen)
|
||||
request.clientConn.Read(domain)
|
||||
clientConn.Read(domain)
|
||||
host = string(domain)
|
||||
default:
|
||||
request.sendReply(addrTypeNotSupported)
|
||||
return errors.New("target address type is not support")
|
||||
request.sendReply(clientConn, addrTypeNotSupported)
|
||||
return ctx, errors.New("target address type is not support")
|
||||
}
|
||||
|
||||
var port uint16
|
||||
binary.Read(request.clientConn, binary.BigEndian, &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
|
||||
binary.Read(clientConn, binary.BigEndian, &port)
|
||||
ctx = context.WithValue(ctx, core.PROXY_CONNECTION_ADDR, host)
|
||||
ctx = context.WithValue(ctx, core.PROXY_CONNECTION_PORT, port)
|
||||
request.sendReply(clientConn, succeeded)
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
// passive mode
|
||||
@ -127,7 +124,7 @@ func (request *Request) handleBind() error {
|
||||
}
|
||||
|
||||
//udp
|
||||
func (request *Request) handleUDP() error {
|
||||
func (request *Request) handleUDP(ctx context.Context, clientConn net.Conn) (context.Context, error) {
|
||||
/*
|
||||
+----+------+------+----------+----------+----------+
|
||||
|RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
|
||||
@ -136,13 +133,13 @@ func (request *Request) handleUDP() error {
|
||||
+----+------+------+----------+----------+----------+
|
||||
*/
|
||||
buf := make([]byte, 3)
|
||||
request.clientConn.Read(buf)
|
||||
clientConn.Read(buf)
|
||||
// relay udp datagram silently, without any notification to the requesting client
|
||||
if buf[2] != 0 {
|
||||
// does not support fragmentation, drop it
|
||||
dummy := make([]byte, maxUDPPacketSize)
|
||||
request.clientConn.Read(dummy)
|
||||
return errors.New("does not support fragmentation, drop")
|
||||
clientConn.Read(dummy)
|
||||
return ctx, errors.New("does not support fragmentation, drop")
|
||||
}
|
||||
return request.doConnect()
|
||||
return request.doConnect(ctx, clientConn)
|
||||
}
|
||||
|
@ -35,25 +35,33 @@ func NewS5Server(globalConfig, clientConfig, pluginConfig map[string]string, Ser
|
||||
func (s5 *S5Server) Start(ctx context.Context) error {
|
||||
// init config of plugin
|
||||
for _, pg := range s5.plugins.AllPgs {
|
||||
pg.InitConfig(s5.globalConfig, s5.clientConfig, s5.pluginConfig)
|
||||
}
|
||||
// run the plugin contains start
|
||||
if core.RunPlugin(ctx, s5.plugins.StartPgs) != nil {
|
||||
return nil
|
||||
if pg.GetConfigName() != nil {
|
||||
pg.InitConfig(s5.globalConfig, s5.clientConfig, s5.pluginConfig, pg.GetConfigName().GetAll())
|
||||
}
|
||||
}
|
||||
|
||||
return core.NewTcpListenerAndProcess(s5.ServerIp+":"+strconv.Itoa(s5.ServerPort), func(c net.Conn) {
|
||||
core.NewTcpListenerAndProcess(s5.ServerIp+":"+strconv.Itoa(s5.ServerPort), func(c net.Conn) {
|
||||
// init ctx value clientConn
|
||||
ctx = context.WithValue(ctx, core.CLIENT_CONNECTION, c)
|
||||
// start run the plugin run
|
||||
if err := core.RunPlugin(ctx, s5.plugins.RunPgs); err != nil {
|
||||
connCtx := context.WithValue(ctx, core.CLIENT_CONNECTION, c)
|
||||
var err error
|
||||
|
||||
// run the plugin contains start
|
||||
if connCtx, err = core.RunPlugin(connCtx, s5.plugins.StartPgs, core.STAGE_START); err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// start run the plugin run
|
||||
if connCtx, err = core.RunPlugin(connCtx, s5.plugins.RunPgs, core.STAGE_RUN); err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// start run the plugin end
|
||||
if err := core.RunPlugin(ctx, s5.plugins.EndPgs); err != nil {
|
||||
if connCtx, err = core.RunPlugin(connCtx, s5.plugins.EndPgs, core.STAGE_END); err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
}, &s5.listener)
|
||||
return nil
|
||||
}
|
||||
|
@ -9,6 +9,10 @@ func TestNewS5Server(t *testing.T) {
|
||||
g := make(map[string]string)
|
||||
c := make(map[string]string)
|
||||
p := make(map[string]string)
|
||||
p["socks5_check_access"] = "true"
|
||||
p["socks5_simple_access_check"] = "true"
|
||||
p["socks5_simple_access_username"] = "111"
|
||||
p["socks5_simple_access_password"] = "222"
|
||||
s5 := NewS5Server(g, c, p, "", 1099)
|
||||
ctx := context.Background()
|
||||
s5.Start(ctx)
|
||||
|
Loading…
x
Reference in New Issue
Block a user