diff --git a/go.mod b/go.mod index 92c638b5..8d0055e6 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/samber/lo v1.38.1 github.com/spf13/cobra v1.7.0 github.com/stretchr/testify v1.8.4 - golang.org/x/crypto v0.14.0 + golang.org/x/crypto v0.15.0 golang.org/x/net v0.17.0 golang.org/x/oauth2 v0.10.0 golang.org/x/sync v0.3.0 @@ -67,8 +67,8 @@ require ( github.com/tjfoc/gmsm v1.4.1 // indirect golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect golang.org/x/mod v0.10.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/tools v0.9.3 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.31.0 // indirect diff --git a/go.sum b/go.sum index 8e2c09c5..49cef0b2 100644 --- a/go.sum +++ b/go.sum @@ -157,8 +157,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o= golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= @@ -210,21 +210,21 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/pkg/config/v1/server.go b/pkg/config/v1/server.go index d91002cb..1b313266 100644 --- a/pkg/config/v1/server.go +++ b/pkg/config/v1/server.go @@ -16,6 +16,7 @@ package v1 import ( "github.com/samber/lo" + "golang.org/x/crypto/ssh" "github.com/fatedier/frp/pkg/config/types" "github.com/fatedier/frp/pkg/util/util" @@ -27,7 +28,7 @@ type SSHTunnelGateway struct { PublicKeyFilesPath string `json:"publicKeyFilesPath,omitempty"` // store all public key file. load all when init - PublicKeyFilesMap map[string]string + PublicKeyFilesMap map[string]ssh.PublicKey } type ServerConfig struct { diff --git a/pkg/config/v1/ssh.go b/pkg/config/v1/ssh.go index d21581ce..440305d4 100644 --- a/pkg/config/v1/ssh.go +++ b/pkg/config/v1/ssh.go @@ -8,6 +8,8 @@ import ( "errors" "os" "path/filepath" + + "golang.org/x/crypto/ssh" ) const ( @@ -45,24 +47,25 @@ func generatePrivateKey() (*rsa.PrivateKey, error) { return privateKey, nil } -func LoadFilesInDirectory(dirPath string) (map[string]string, error) { - fileMap := make(map[string]string) - +func LoadSSHPublicKeyFilesInDir(dirPath string) (map[string]ssh.PublicKey, error) { + fileMap := make(map[string]ssh.PublicKey) files, err := os.ReadDir(dirPath) if err != nil { return nil, err } for _, file := range files { - filename := file.Name() - filePath := filepath.Join(dirPath, filename) - + filePath := filepath.Join(dirPath, file.Name()) content, err := os.ReadFile(filePath) if err != nil { return nil, err } - fileMap[filename] = string(content) + parsedAuthorizedKey, _, _, _, err := ssh.ParseAuthorizedKey(content) + if err != nil { + continue + } + fileMap[ssh.FingerprintSHA256(parsedAuthorizedKey)] = parsedAuthorizedKey } return fileMap, nil diff --git a/server/ssh_service.go b/pkg/ssh/service.go similarity index 99% rename from server/ssh_service.go rename to pkg/ssh/service.go index 90c68ed6..800f1db5 100644 --- a/server/ssh_service.go +++ b/pkg/ssh/service.go @@ -1,4 +1,4 @@ -package server +package ssh import ( "encoding/binary" diff --git a/server/vclient_service.go b/pkg/ssh/vclient.go similarity index 98% rename from server/vclient_service.go rename to pkg/ssh/vclient.go index 5c012b90..a08101ae 100644 --- a/server/vclient_service.go +++ b/pkg/ssh/vclient.go @@ -1,4 +1,4 @@ -package server +package ssh import ( "context" @@ -174,8 +174,6 @@ func (svr *VirtualService) GetWorkConn() (workConn net.Conn, err error) { Port: uint32(svr.pxyCfg.(*v1.TCPProxyConfig).RemotePort), } - log.Info("get work conn payload: %v", payload) - channel, reqs, err := svr.sshSvc.SSHConn().OpenChannel(ChannelTypeServerOpenChannel, ssh.Marshal(payload)) if err != nil { return nil, fmt.Errorf("open ssh channel error: %v", err) diff --git a/server/service.go b/server/service.go index abfa2d7d..1d33897e 100644 --- a/server/service.go +++ b/server/service.go @@ -24,6 +24,7 @@ import ( "net" "net/http" "os" + "reflect" "strconv" "time" @@ -40,6 +41,7 @@ import ( "github.com/fatedier/frp/pkg/msg" "github.com/fatedier/frp/pkg/nathole" plugin "github.com/fatedier/frp/pkg/plugin/server" + frpssh "github.com/fatedier/frp/pkg/ssh" "github.com/fatedier/frp/pkg/transport" "github.com/fatedier/frp/pkg/util/log" utilnet "github.com/fatedier/frp/pkg/util/net" @@ -209,7 +211,7 @@ func NewService(cfg *v1.ServerConfig) (svr *Service, err error) { if cfg.SSHTunnelGateway.BindPort > 0 { if cfg.SSHTunnelGateway.PublicKeyFilesPath != "" { - cfg.SSHTunnelGateway.PublicKeyFilesMap, err = v1.LoadFilesInDirectory(cfg.SSHTunnelGateway.PublicKeyFilesPath) + cfg.SSHTunnelGateway.PublicKeyFilesMap, err = v1.LoadSSHPublicKeyFilesInDir(cfg.SSHTunnelGateway.PublicKeyFilesPath) if err != nil { return nil, fmt.Errorf("load ssh all public key files error: %v", err) } @@ -220,20 +222,14 @@ func NewService(cfg *v1.ServerConfig) (svr *Service, err error) { NoClientAuth: lo.If(cfg.SSHTunnelGateway.PublicKeyFilesPath == "", true).Else(false), PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { - keyContent, ok := cfg.SSHTunnelGateway.PublicKeyFilesMap[ssh.FingerprintSHA256(key)] + parsedAuthorizedKey, ok := cfg.SSHTunnelGateway.PublicKeyFilesMap[ssh.FingerprintSHA256(key)] if !ok { return nil, errors.New("cannot find public key file") } - parsedAuthorizedKey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(keyContent)) - if err != nil { - return nil, err - } - if key.Type() == parsedAuthorizedKey.Type() && bytes.Equal(key.Marshal(), parsedAuthorizedKey.Marshal()) { + if key.Type() == parsedAuthorizedKey.Type() && reflect.DeepEqual(parsedAuthorizedKey, key) { return &ssh.Permissions{ - Extensions: map[string]string{ - ssh.FingerprintSHA256(key): keyContent, - }, + Extensions: map[string]string{}, }, nil } return nil, fmt.Errorf("unknown public key for %q", conn.User()) @@ -587,7 +583,7 @@ func (svr *Service) HandleSSHListener(listener net.Listener) { pxyPayloadCh := make(chan v1.ProxyConfigurer) replyCh := make(chan interface{}) - ss, err := NewSSHService(tcpConn, svr.sshConfig, pxyPayloadCh, replyCh) + ss, err := frpssh.NewSSHService(tcpConn, svr.sshConfig, pxyPayloadCh, replyCh) if err != nil { log.Error("new ssh service error: %v", err) continue @@ -600,7 +596,8 @@ func (svr *Service) HandleSSHListener(listener net.Listener) { ctx := context.Background() - vs, err := NewVirtualService(ctx, v1.ClientCommonConfig{}, *svr.cfg, + // TODO fill client common config and login msg + vs, err := frpssh.NewVirtualService(ctx, v1.ClientCommonConfig{}, *svr.cfg, msg.Login{User: v1.SSHClientLoginUserPrefix + tcpConn.RemoteAddr().String()}, svr.rc, pxyCfg, ss, replyCh) if err != nil {