-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.go
More file actions
124 lines (112 loc) · 2.83 KB
/
server.go
File metadata and controls
124 lines (112 loc) · 2.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package main
import (
"fmt"
"io/ioutil"
"log"
"net"
"golang.org/x/crypto/ssh"
"github.com/grt1st/sshjumper/conf"
"github.com/grt1st/sshjumper/handlers"
)
func main() {
Listen(conf.ServerAddr)
}
func Listen(addr string) {
// listen
localListener, err := net.Listen("tcp", addr)
if err != nil {
log.Fatalf("net.Listen failed: %v\n", err)
} else {
log.Printf("net.Listen at %v\n", addr)
}
for {
// get connect
localConn, err := localListener.Accept()
if err != nil {
fmt.Printf("localListener.Accept failed: %v\n", err)
}
go func() {
CreatePortalSession(localConn)
}()
}
}
// CreatePortalSession 创建命令监听
func CreatePortalSession(conn net.Conn) {
// server config
conf.InitSSHPublicKey()
config := ssh.ServerConfig{
PasswordCallback: conf.ConnectSSHPassword,
PublicKeyCallback: conf.ConnectSSHPublicKey,
}
// private key
keyBytes, err := ioutil.ReadFile(conf.PrivateKeyPath)
if err != nil {
panic(err)
}
key, err := ssh.ParsePrivateKey(keyBytes)
if err != nil {
panic(err)
}
config.AddHostKey(key)
// 创建
serverConn, chans, reqs, err := ssh.NewServerConn(conn, &config)
if err != nil {
log.Printf("create sever conn failed: %v\n", err)
} else {
log.Printf("create server conn from %s\n", serverConn.RemoteAddr())
}
// 消费
go ssh.DiscardRequests(reqs)
// 消费
go func(chans <-chan ssh.NewChannel) {
for newChannel := range chans {
channel, requests, err := newChannel.Accept()
if err != nil {
log.Printf("newChannel.Accept failed: %v\n", err)
continue // todo: handler error
}
go func(in <-chan *ssh.Request) {
for req := range in {
switch req.Type {
case "shell":
go handlers.HandlePty(channel, serverConn)
_ = req.Reply(req.Type == "shell", req.Payload)
case "exec":
var msg execMsg
if err = ssh.Unmarshal(req.Payload, &msg); err != nil {
log.Printf("error parsing ssh execMsg: %s\n", err)
_ = req.Reply(false, nil)
} else {
go func(msg execMsg, ch ssh.Channel) {
// ch can be used as a ReadWriteCloser if there should be interactivity
handlers.HandleExec(msg.Command, ch)
ex := exitStatusMsg{
Status: 0,
}
// return the status code
if _, err := ch.SendRequest("exit-status", false, ssh.Marshal(&ex)); err != nil {
log.Printf("unable to send status: %v", err)
}
_ = ch.Close()
}(msg, channel)
_ = req.Reply(true, nil) // tell the other end that we can run the request
}
//case "env":
// ignore
//case "pty-req":
// todo: change window size
default:
log.Printf("req_type=%v, payload=%v", req.Type, string(req.Payload))
}
}
}(requests)
}
}(chans)
}
type exitStatusMsg struct {
Status uint32
}
// RFC 4254 Section 6.5.
type execMsg struct {
Command string
}