summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrunoneall <runoneall@serv00.net>2025-09-11 11:19:12 +0200
committerrunoneall <runoneall@serv00.net>2025-09-11 11:19:12 +0200
commit59c5a6c4950d340d248431b84452d86329024d76 (patch)
tree71d5e243090a319f35c6b35046e81ddf7271dc35
parent1ac4476d0a226c319200720a6ff63a5471bdc104 (diff)
add ssh server
-rw-r--r--.gitignore5
-rw-r--r--go.mod8
-rw-r--r--go.sum6
-rw-r--r--init.go41
-rw-r--r--main.go67
-rw-r--r--shell.go70
6 files changed, 195 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index 78b09d0..9a2c438 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,7 @@
server.properties
Starter.class
starter.jar
-tmp/ \ No newline at end of file
+
+tmp/
+
+mc-ssh-server.exe \ No newline at end of file
diff --git a/go.mod b/go.mod
index d9e8f04..585f2f0 100644
--- a/go.mod
+++ b/go.mod
@@ -1,3 +1,9 @@
-module ssh-server
+module mc-ssh-server
go 1.25.1
+
+require (
+ github.com/magiconair/properties v1.8.10 // indirect
+ golang.org/x/crypto v0.42.0 // indirect
+ golang.org/x/sys v0.36.0 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..6edb2b3
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,6 @@
+github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
+github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
+golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
+golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
+golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
+golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
diff --git a/init.go b/init.go
new file mode 100644
index 0000000..37ed53a
--- /dev/null
+++ b/init.go
@@ -0,0 +1,41 @@
+package main
+
+import (
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/x509"
+ "encoding/pem"
+ "fmt"
+)
+
+func init_genkey() (*pem.Block, *pem.Block) {
+ privateKey, err := rsa.GenerateKey(rand.Reader, 4096)
+ if err != nil {
+ panic(fmt.Errorf("不能生成密钥: %v", err))
+ }
+
+ privateKeyBytes := x509.MarshalPKCS1PrivateKey(privateKey)
+ privateKeyBlock := &pem.Block{
+ Type: "RSA PRIVATE KEY",
+ Bytes: privateKeyBytes,
+ }
+
+ publicKeyBytes, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey)
+ if err != nil {
+ panic(fmt.Errorf("不能解析公钥: %v", err))
+ }
+
+ publicKeyBlock := &pem.Block{
+ Type: "PUBLIC KEY",
+ Bytes: publicKeyBytes,
+ }
+
+ return privateKeyBlock, publicKeyBlock
+}
+
+var privatePEM []byte
+
+func init() {
+ privateKeyBlock, _ := init_genkey()
+ privatePEM = pem.EncodeToMemory(privateKeyBlock)
+}
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..1bbe285
--- /dev/null
+++ b/main.go
@@ -0,0 +1,67 @@
+package main
+
+import (
+ "fmt"
+ "net"
+
+ "github.com/magiconair/properties"
+ "golang.org/x/crypto/ssh"
+)
+
+func main() {
+
+ // 解析 server.properties
+ conf := properties.MustLoadFile("server.properties", properties.UTF8)
+ var SSH_SERVER struct {
+ Host string
+ Port string
+ User string
+ Pass string
+ config *ssh.ServerConfig
+ }
+
+ SSH_SERVER.Host = conf.MustGetString("server-ip")
+ SSH_SERVER.Port = conf.MustGetString("server-port")
+ SSH_SERVER.User = conf.MustGetString("term-user")
+ SSH_SERVER.Pass = conf.MustGetString("term-pass")
+
+ // 创建 ssh 密码认证
+ SSH_SERVER.config = &ssh.ServerConfig{
+ PasswordCallback: func(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
+ if conn.User() == SSH_SERVER.User && string(password) == SSH_SERVER.Pass {
+ return nil, nil
+ }
+
+ return nil, ssh.ErrNoAuth
+ },
+ }
+
+ // 创建 ssh 服务器密钥
+ privateKeySigner, err := ssh.ParsePrivateKey(privatePEM)
+ if err != nil {
+ panic(fmt.Errorf("不能解析私钥: %v", err))
+ }
+
+ SSH_SERVER.config.AddHostKey(privateKeySigner)
+
+ // 在指定端口开启服务
+ address := net.JoinHostPort(SSH_SERVER.Host, SSH_SERVER.Port)
+
+ listener, err := net.Listen("tcp", address)
+ if err != nil {
+ panic(fmt.Errorf("不能在 %s 上创建服务: %v", address, err))
+ }
+
+ fmt.Println("Server Address:", address)
+
+ // 连接到系统 shell
+ for {
+ conn, err := listener.Accept()
+ if err != nil {
+ fmt.Println("Can not accept connection:", err)
+ }
+
+ go shell(conn, SSH_SERVER.config)
+ }
+
+}
diff --git a/shell.go b/shell.go
new file mode 100644
index 0000000..3492b33
--- /dev/null
+++ b/shell.go
@@ -0,0 +1,70 @@
+package main
+
+import (
+ "fmt"
+ "net"
+ "os"
+ "os/exec"
+
+ "golang.org/x/crypto/ssh"
+)
+
+func shell(conn net.Conn, config *ssh.ServerConfig) {
+ sshConn, chans, reqs, err := ssh.NewServerConn(conn, config)
+ if err != nil {
+ fmt.Println("不能创建连接:", err)
+ return
+ }
+ defer sshConn.Close()
+
+ fmt.Println("New connection from", sshConn.RemoteAddr(), "with client version", sshConn.ClientVersion())
+
+ go ssh.DiscardRequests(reqs)
+
+ for newChannel := range chans {
+ if newChannel.ChannelType() != "session" {
+ newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
+ continue
+ }
+
+ channel, requests, err := newChannel.Accept()
+ if err != nil {
+ fmt.Println("Can not accept channel:", err)
+ continue
+ }
+ defer channel.Close()
+
+ shell := os.Getenv("SHELL")
+ if shell == "" {
+ shell = "cmd.exe"
+ }
+
+ command := exec.Command(shell)
+ command.Stdin = channel
+ command.Stdout = channel
+ command.Stderr = channel
+
+ if err := command.Start(); err != nil {
+ fmt.Println("Failed to start shell:", err)
+ return
+ }
+
+ go func() {
+ if err := command.Wait(); err != nil {
+ fmt.Println("Run shell failed:", err)
+ }
+ channel.Close()
+ }()
+
+ go func() {
+ for req := range requests {
+ switch req.Type {
+ case "shell":
+ req.Reply(true, nil)
+ default:
+ req.Reply(false, nil)
+ }
+ }
+ }()
+ }
+}