Skip to content

Commit e629bdf

Browse files
committed
perf: refactor virutal app same like applet
1 parent e1a6213 commit e629bdf

10 files changed

Lines changed: 5202 additions & 3367 deletions

File tree

docker-compose.yaml.example

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,31 @@
1-
version: "3.0"
2-
31
networks:
4-
guacd:
2+
lion:
53
driver: bridge
64

75
services:
8-
guacd:
9-
image: jumpserver/guacd:1.4.0
10-
container_name: guacd
6+
lion:
7+
image: jumpserver/lion:dev
8+
build:
9+
context: .
10+
dockerfile: Dockerfile
11+
args:
12+
VERSION: dev
13+
container_name: jms_lion
1114
ports:
15+
- "8081:8081"
1216
- "4822:4822"
1317
environment:
18+
CORE_HOST: ${CORE_HOST:-http://10.0.0.5:8080}
19+
BOOTSTRAP_TOKEN: ${BOOTSTRAP_TOKEN:-ICAgICAgICBUWCBl}
20+
BIND_HOST: 0.0.0.0
21+
HTTPD_PORT: 8081
22+
LOG_LEVEL: DEBUG
23+
GUA_HOST: 127.0.0.1
24+
GUA_PORT: 4822
25+
SHARE_ROOM_TYPE: local
1426
GUACD_LOG_LEVEL: debug
1527
networks:
16-
- guacd
28+
- lion
1729
restart: always
1830
volumes:
1931
- ./data/:/opt/lion/data/:rw # /opt/lion/-> 本地项目路径, 修改 ./data 目录权限为777

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,5 @@ require (
8888
golang.org/x/time v0.12.0 // indirect
8989
google.golang.org/protobuf v1.36.11 // indirect
9090
)
91+
92+
replace github.com/jumpserver-dev/sdk-go => ../sdk-go

main.go

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,19 @@ func main() {
6161
config.Setup(configPath)
6262
logger.SetupLogger(config.GlobalConfig)
6363
jmsService := MustJMService()
64-
pandaClient := NewPandaClient(*config.GlobalConfig)
64+
pandaClientFactory := NewPandaClientFactory(*config.GlobalConfig)
65+
pandaClient := pandaClientFactory(config.GlobalConfig.PandaHost)
6566
bootstrap(jmsService)
6667
tunnelService := tunnel.GuacamoleTunnelServer{
6768
Cache: &tunnel.GuaTunnelCacheManager{
6869
GuaTunnelCache: NewGuaTunnelCache(),
6970
},
7071
JmsService: jmsService,
71-
SessionService: &session.Server{JmsService: jmsService,
72-
PandaClient: pandaClient},
72+
SessionService: &session.Server{
73+
JmsService: jmsService,
74+
PandaClient: pandaClient,
75+
PandaClientFactory: pandaClientFactory,
76+
},
7377
}
7478
eng := registerRouter(jmsService, &tunnelService)
7579
go runHeartTask(jmsService, tunnelService.Cache)
@@ -631,11 +635,16 @@ func MustValidKey(key model.AccessKey) model.AccessKey {
631635
}
632636

633637
func NewPandaClient(cfg config.Config) *panda.Client {
634-
pandaHost := cfg.PandaHost
638+
return NewPandaClientFactory(cfg)(cfg.PandaHost)
639+
}
640+
641+
func NewPandaClientFactory(cfg config.Config) func(string) *panda.Client {
635642
var key model.AccessKey
636643
if err := key.LoadFromFile(cfg.AccessKeyFilePath); err != nil {
637644
logger.Errorf("Create panda client failed: loading access key err %s", err)
638-
return nil
645+
return func(string) *panda.Client { return nil }
646+
}
647+
return func(pandaHost string) *panda.Client {
648+
return panda.NewClient(pandaHost, key, cfg.IgnoreVerifyCerts)
639649
}
640-
return panda.NewClient(pandaHost, key, cfg.IgnoreVerifyCerts)
641650
}

pkg/gateway/domain.go

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ type DomainGateway struct {
2626
DstAddr string // 10.0.0.1:3389
2727

2828
sshClient *gossh.Client
29+
jumpClient *gossh.Client
2930
SelectedGateway *model.Gateway
31+
Destination *model.Gateway
3032

3133
ln net.Listener
3234

@@ -40,10 +42,10 @@ func (d *DomainGateway) run() {
4042
if err != nil {
4143
break
4244
}
43-
logger.Infof("Accept new conn by gateway %s ", d.SelectedGateway.Name)
45+
logger.Infof("Accept new conn by SSH forwarder %s ", d.Name())
4446
go d.handlerConn(con)
4547
}
46-
logger.Infof("Stop proxy by gateway %s", d.SelectedGateway.Name)
48+
logger.Infof("Stop proxy by SSH forwarder %s", d.Name())
4749
}
4850

4951
func (d *DomainGateway) handlerConn(srcCon net.Conn) {
@@ -82,6 +84,16 @@ func (d *DomainGateway) GetListenAddr() *net.TCPAddr {
8284
}
8385

8486
func (d *DomainGateway) getAvailableGateway() bool {
87+
if d.Destination != nil {
88+
sshClient, jumpClient, err := d.createDestinationSSHClient()
89+
if err != nil {
90+
logger.Errorf("Dial SSH destination %s err: %s", d.Destination.Name, err)
91+
return false
92+
}
93+
d.sshClient = sshClient
94+
d.jumpClient = jumpClient
95+
return true
96+
}
8597
if d.SelectedGateway != nil {
8698
sshClient, err := d.createGatewaySSHClient(d.SelectedGateway)
8799
if err != nil {
@@ -94,7 +106,39 @@ func (d *DomainGateway) getAvailableGateway() bool {
94106
}
95107
return false
96108
}
109+
110+
func (d *DomainGateway) createDestinationSSHClient() (*gossh.Client, *gossh.Client, error) {
111+
if d.SelectedGateway == nil {
112+
client, err := d.createGatewaySSHClient(d.Destination)
113+
return client, nil, err
114+
}
115+
jumpClient, err := d.createGatewaySSHClient(d.SelectedGateway)
116+
if err != nil {
117+
return nil, nil, err
118+
}
119+
addr := gatewaySSHAddress(d.Destination)
120+
conn, err := jumpClient.Dial("tcp", addr)
121+
if err != nil {
122+
_ = jumpClient.Close()
123+
return nil, nil, err
124+
}
125+
_ = conn.SetDeadline(time.Now().Add(miniTimeout))
126+
clientConn, chans, reqs, err := gossh.NewClientConn(
127+
conn, addr, gatewaySSHConfig(d.Destination),
128+
)
129+
if err != nil {
130+
_ = conn.Close()
131+
_ = jumpClient.Close()
132+
return nil, nil, err
133+
}
134+
_ = conn.SetDeadline(time.Time{})
135+
return gossh.NewClient(clientConn, chans, reqs), jumpClient, nil
136+
}
97137
func (d *DomainGateway) createGatewaySSHClient(gateway *model.Gateway) (*gossh.Client, error) {
138+
return gossh.Dial("tcp", gatewaySSHAddress(gateway), gatewaySSHConfig(gateway))
139+
}
140+
141+
func gatewaySSHConfig(gateway *model.Gateway) *gossh.ClientConfig {
98142
auths := make([]gossh.AuthMethod, 0, 3)
99143
loginAccount := gateway.Account
100144
if loginAccount.IsSSHKey() {
@@ -110,26 +154,45 @@ func (d *DomainGateway) createGatewaySSHClient(gateway *model.Gateway) (*gossh.C
110154
return []string{loginAccount.Secret}, nil
111155
}))
112156
}
113-
sshConfig := gossh.ClientConfig{
157+
return &gossh.ClientConfig{
114158
User: loginAccount.Username,
115159
Auth: auths,
116160
HostKeyCallback: NewTrustHostKeyCallback(),
117161
Config: createSSHConfig(),
118162
Timeout: miniTimeout,
119163
HostKeyAlgorithms: allHostKeyAlgorithms(),
120164
}
165+
}
166+
167+
func gatewaySSHAddress(gateway *model.Gateway) string {
121168
port := gateway.Protocols.GetProtocolPort("ssh")
122-
addr := net.JoinHostPort(gateway.Address, strconv.Itoa(port))
123-
return gossh.Dial("tcp", addr, &sshConfig)
169+
return net.JoinHostPort(gateway.Address, strconv.Itoa(port))
170+
}
171+
172+
func (d *DomainGateway) Name() string {
173+
if d.Destination != nil {
174+
return d.Destination.Name
175+
}
176+
if d.SelectedGateway != nil {
177+
return d.SelectedGateway.Name
178+
}
179+
return "unknown"
124180
}
125181
func (d *DomainGateway) Stop() {
126182
d.closeOnce()
127183
}
128184

129185
func (d *DomainGateway) closeOnce() {
130186
d.once.Do(func() {
131-
_ = d.ln.Close()
132-
_ = d.sshClient.Close()
187+
if d.ln != nil {
188+
_ = d.ln.Close()
189+
}
190+
if d.sshClient != nil {
191+
_ = d.sshClient.Close()
192+
}
193+
if d.jumpClient != nil {
194+
_ = d.jumpClient.Close()
195+
}
133196
})
134197
}
135198

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package gateway
2+
3+
import (
4+
"net"
5+
"os"
6+
"strconv"
7+
"testing"
8+
"time"
9+
10+
"github.com/jumpserver-dev/sdk-go/model"
11+
)
12+
13+
func TestDomainGatewaySSHForwardIntegration(t *testing.T) {
14+
host := os.Getenv("LION_SSH_TEST_HOST")
15+
keyFile := os.Getenv("LION_SSH_TEST_KEY_FILE")
16+
destination := os.Getenv("LION_SSH_TEST_DESTINATION")
17+
if host == "" || keyFile == "" || destination == "" {
18+
t.Skip("set LION_SSH_TEST_HOST, LION_SSH_TEST_KEY_FILE and LION_SSH_TEST_DESTINATION")
19+
}
20+
port, err := strconv.Atoi(os.Getenv("LION_SSH_TEST_PORT"))
21+
if err != nil || port == 0 {
22+
port = 22
23+
}
24+
secret, err := os.ReadFile(keyFile)
25+
if err != nil {
26+
t.Fatal(err)
27+
}
28+
sshTarget := func(name, address string, sshPort int) *model.Gateway {
29+
return &model.Gateway{
30+
Name: name,
31+
Address: address,
32+
Protocols: model.Protocols{{Name: "ssh", Port: sshPort}},
33+
Account: model.Account{BaseAccount: model.BaseAccount{
34+
Username: "root",
35+
Secret: string(secret),
36+
SecretType: model.LabelValue{Value: "ssh_key"},
37+
}},
38+
}
39+
}
40+
forwarder := DomainGateway{
41+
DstAddr: destination,
42+
Destination: sshTarget("integration-provider", host, port),
43+
}
44+
if jumpHost := os.Getenv("LION_SSH_TEST_JUMP_HOST"); jumpHost != "" {
45+
jumpPort, err := strconv.Atoi(os.Getenv("LION_SSH_TEST_JUMP_PORT"))
46+
if err != nil || jumpPort == 0 {
47+
jumpPort = 22
48+
}
49+
forwarder.SelectedGateway = sshTarget("integration-gateway", jumpHost, jumpPort)
50+
}
51+
if err := forwarder.Start(); err != nil {
52+
t.Fatal(err)
53+
}
54+
defer forwarder.Stop()
55+
56+
conn, err := net.DialTimeout("tcp", forwarder.GetListenAddr().String(), 5*time.Second)
57+
if err != nil {
58+
t.Fatalf("dial forwarded destination: %v", err)
59+
}
60+
_ = conn.Close()
61+
}

0 commit comments

Comments
 (0)