1 Commits 0560c6f970 ... a38ebf2763

Author SHA1 Message Date
  zry a38ebf2763 Commit at 2018-08-10 01:26. 5 years ago
9 changed files with 271 additions and 0 deletions
  1. 2 0
      .gitignore
  2. 8 0
      .idea/goSBNAT.iml
  3. 8 0
      .idea/modules.xml
  4. 6 0
      .idea/vcs.xml
  5. 26 0
      Tests/SimpleIntermediateServer/main.go
  6. 50 0
      Tools/HostKeyGen/main.go
  7. 115 0
      imsvr/imsvr.go
  8. 2 0
      imsvr/misc.go
  9. 54 0
      imsvr/svrcfg.go

+ 2 - 0
.gitignore

@@ -24,3 +24,5 @@ _testmain.go
 *.test
 *.prof
 
+*.key
+

+ 8 - 0
.idea/goSBNAT.iml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/goSBNAT.iml" filepath="$PROJECT_DIR$/.idea/goSBNAT.iml" />
+    </modules>
+  </component>
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

+ 26 - 0
Tests/SimpleIntermediateServer/main.go

@@ -0,0 +1,26 @@
+package main
+
+import (
+	"git.swzry.com/zry/goSBNAT/imsvr"
+	"io/ioutil"
+	"fmt"
+	"golang.org/x/crypto/ssh"
+)
+
+func main()  {
+	svrcfg := imsvr.ServerConfig{
+		BindAddress: "0.0.0.0:1819",
+		MaxAuthTries: 5,
+	}
+	hostkeyfile, err := ioutil.ReadFile("sshhost.key")
+	if err != nil {
+		fmt.Println("Failed Load Host Key File: ", err)
+		return
+	}
+	hostkey, err := ssh.ParsePrivateKey(hostkeyfile)
+	if err != nil{
+		fmt.Println("Failed Load Host Key: ", err)
+		return
+	}
+	svrcfg.AddHostKey(hostkey)
+}

+ 50 - 0
Tools/HostKeyGen/main.go

@@ -0,0 +1,50 @@
+package main
+
+import (
+	"crypto/rsa"
+	"fmt"
+	"crypto/x509"
+	"encoding/pem"
+	"os"
+	"crypto/rand"
+	"flag"
+)
+
+func main(){
+	var keyfilename string
+	var keylen int
+	var help bool
+	flag.IntVar(&keylen, "l", 2048, "Key Length (default: 2048)")
+	flag.StringVar(&keyfilename, "o", "sshhost.key", "Output File Name (default: sshhost.key)")
+	flag.BoolVar(&help, "h", false, "Show Help")
+	if help{
+		fmt.Println("Usage: HostKeyGen [-h] [-l <keylenth>] [-o <out_file>]")
+		flag.PrintDefaults()
+		return
+	}
+	GenerateRSAKey(keyfilename, keylen)
+}
+
+func GenerateRSAKey(keyfn string,keyLength int) {
+	privateKey, err := rsa.GenerateKey(rand.Reader, keyLength)
+	if err != nil {
+		fmt.Println("Failed to Generate RSA Private Key: ", err)
+		return
+	}
+	derStream := x509.MarshalPKCS1PrivateKey(privateKey)
+	block := &pem.Block{
+		Type:  "RSA PRIVATE KEY",
+		Bytes: derStream,
+	}
+	file, err := os.Create(keyfn)
+	if err != nil {
+		fmt.Println("Failed to Create Key File: ", err)
+		return
+	}
+	err = pem.Encode(file, block)
+	if err != nil {
+		fmt.Println("Failed to Encode Key: ", err)
+		return
+	}
+	fmt.Println("SSH Host Key Generated Successfully..")
+}

+ 115 - 0
imsvr/imsvr.go

@@ -0,0 +1,115 @@
+package imsvr
+
+import (
+	"github.com/xtaci/kcp-go"
+	"net"
+	"golang.org/x/crypto/ssh"
+	"errors"
+	"bytes"
+)
+
+const VERSION string = "1.0"
+
+type Server struct{
+	kcpListener *net.Listener
+	sshConfig *ssh.ServerConfig
+	isPasswdAuthSet bool
+	cliAuthCallback func(username string, password []byte) bool
+	sbnatAuthList map[string][]byte
+}
+
+func NewServer(conf *ServerConfig) (*Server, error) {
+	kcplis,err := kcp.Listen(conf.BindAddress)
+	if err != nil {
+		return nil, err
+	}
+	sshcfg := &ssh.ServerConfig{
+		NoClientAuth: false,
+		MaxAuthTries: conf.MaxAuthTries,
+		ServerVersion: "goSBNAT-Intermediate-Server-" + VERSION,
+	}
+	if conf.hostkeys == nil {
+		return nil, errors.New("NoHostKeySpecified")
+	}
+	for _,v := range conf.hostkeys {
+		sshcfg.AddHostKey(v)
+	}
+	svr := &Server{
+		kcpListener: &kcplis,
+		sshConfig: sshcfg,
+	}
+	if conf.ovrSSHKeyboardInteractiveCallback {
+		svr.sshConfig.KeyboardInteractiveCallback = conf.ocSSHKeyboardInteractiveCallback
+	}else {
+		svr.sshConfig.KeyboardInteractiveCallback = svr.sshKbdIaCb
+	}
+	if conf.ovrSSHAuthLogCallback {
+		svr.sshConfig.AuthLogCallback = conf.ocSSHAuthLogCallback
+	}else{
+		svr.sshConfig.AuthLogCallback = svr.sshAuthLogCb
+	}
+	if conf.ovrSSHPasswordCallback {
+		svr.sshConfig.PasswordCallback = conf.ocSSHPasswordCallback
+	}else {
+		svr.sshConfig.PasswordCallback = svr.sshPwdCb
+	}
+	if conf.ovrSSHPublicKeyCallback {
+		svr.sshConfig.PublicKeyCallback = conf.ocSSHPublicKeyCallback
+	}else {
+		svr.sshConfig.PublicKeyCallback = svr.sshPubKeyCb
+	}
+	svr.sbnatAuthList = make(map[string][]byte)
+	return svr, nil
+}
+
+func (this *Server) sshKbdIaCb(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error){
+	return nil, errors.New("KeyboardInteractiveAuthNotSupport")
+}
+
+func (this *Server) sshAuthLogCb(conn ssh.ConnMetadata, method string, err error){
+	return
+}
+
+func (this *Server) sshPwdCb(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
+	if this.cliAuthCallback == nil {
+		return nil, errors.New("NoClientAuthCallback")
+	}
+	if this.cliAuthCallback(conn.User(), password) {
+		perm := &ssh.Permissions{
+			CriticalOptions: make(map[string]string),
+			Extensions: make(map[string]string),
+		}
+		perm.CriticalOptions["type"] = "client"
+		perm.CriticalOptions["user"] = conn.User()
+		return perm, nil
+	}else {
+		return nil, errors.New("ClientAuthFailed")
+	}
+}
+
+func (this *Server) sshPubKeyCb(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
+	v, ok := this.sbnatAuthList[conn.User()]
+	if ok {
+		if bytes.Equal(v, key.Marshal()) {
+			perm := &ssh.Permissions{
+				CriticalOptions: make(map[string]string),
+				Extensions: make(map[string]string),
+			}
+			perm.CriticalOptions["type"] = "sbnat"
+			perm.CriticalOptions["user"] = conn.User()
+			return perm, nil
+		}else {
+			return nil, errors.New("FailedAuthSBNAT")
+		}
+	}else{
+		return nil, errors.New("FailedAuthSBNAT")
+	}
+}
+
+func (this *Server) AddAuthOfSBNAT(servername string, pubkey ssh.PublicKey) {
+	this.sbnatAuthList[servername] = pubkey.Marshal()
+}
+
+func (this *Server) RegistClientAuthCallback(cb func(username string, password []byte) bool) {
+	this.cliAuthCallback = cb
+}

+ 2 - 0
imsvr/misc.go

@@ -0,0 +1,2 @@
+package imsvr
+

+ 54 - 0
imsvr/svrcfg.go

@@ -0,0 +1,54 @@
+package imsvr
+
+import "golang.org/x/crypto/ssh"
+
+type ServerConfig struct {
+	BindAddress string
+	MaxAuthTries int
+	hostkeys []ssh.Signer
+	ovrSSHPasswordCallback bool
+	ovrSSHPublicKeyCallback bool
+	ovrSSHKeyboardInteractiveCallback bool
+	ovrSSHAuthLogCallback bool
+	ocSSHPasswordCallback func(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error)
+	ocSSHPublicKeyCallback func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error)
+	ocSSHKeyboardInteractiveCallback func(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error)
+	ocSSHAuthLogCallback func(conn ssh.ConnMetadata, method string, err error)
+}
+
+func (c *ServerConfig) AddHostKey(key ssh.Signer) {
+	if c.hostkeys == nil {
+		c.hostkeys = make([]ssh.Signer, 1)
+		c.hostkeys[0] = key
+	}else {
+		c.hostkeys = append(c.hostkeys, key)
+	}
+}
+
+func (c *ServerConfig) OverrideSSHPasswordCallback(
+	cb func(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error),
+){
+	c.ovrSSHPasswordCallback = true
+	c.ocSSHPasswordCallback = cb
+}
+
+func (c *ServerConfig) OverrideSSHPublicKeyCallback(
+	cb func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error),
+){
+	c.ovrSSHPublicKeyCallback = true
+	c.ocSSHPublicKeyCallback = cb
+}
+
+func (c *ServerConfig) OverrideSSHKeyboardInteractiveCallbakc(
+	cb func(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error),
+){
+	c.ovrSSHKeyboardInteractiveCallback = true
+	c.ocSSHKeyboardInteractiveCallback = cb
+}
+
+func (c *ServerConfig) OverrideSSHAuthLogCallback(
+	cb func(conn ssh.ConnMetadata, method string, err error),
+){
+	c.ovrSSHAuthLogCallback = true
+	c.ocSSHAuthLogCallback = cb
+}