Skip to content

Commit fdd7722

Browse files
committed
feat: Support enabling proxy when adding nodes
1 parent 4e7b654 commit fdd7722

File tree

3 files changed

+154
-113
lines changed

3 files changed

+154
-113
lines changed

core/utils/cloud_storage/sftp.go

Lines changed: 0 additions & 103 deletions
This file was deleted.

core/utils/ssh/http.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package ssh
2+
3+
import (
4+
"bufio"
5+
"crypto/tls"
6+
"encoding/base64"
7+
"fmt"
8+
"net"
9+
"strings"
10+
"time"
11+
12+
"github.com/1Panel-dev/1Panel/core/global"
13+
)
14+
15+
type HTTPProxyDialer struct {
16+
Type string
17+
URL string
18+
User string
19+
Password string
20+
}
21+
22+
func HTTPDial(dialer HTTPProxyDialer, network, addr string) (net.Conn, error) {
23+
var conn net.Conn
24+
var err error
25+
26+
global.LOG.Debugf("Dialing HTTP proxy %s for %s", dialer.URL, addr)
27+
dialer.URL = strings.TrimPrefix(dialer.URL, dialer.Type+"://")
28+
if dialer.Type == "https" {
29+
conn, err = tls.DialWithDialer(
30+
&net.Dialer{Timeout: 30 * time.Second},
31+
network,
32+
dialer.URL,
33+
&tls.Config{InsecureSkipVerify: false},
34+
)
35+
} else {
36+
conn, err = net.DialTimeout(network, dialer.URL, 30*time.Second)
37+
}
38+
if err != nil {
39+
return nil, err
40+
}
41+
conn.SetDeadline(time.Now().Add(30 * time.Second))
42+
connectReq := fmt.Sprintf("CONNECT %s HTTP/1.1\r\n", addr)
43+
connectReq += fmt.Sprintf("Host: %s\r\n", addr)
44+
connectReq += "User-Agent: Go-ssh-client/1.0\r\n"
45+
46+
if dialer.User != "" {
47+
auth := base64.StdEncoding.EncodeToString(
48+
[]byte(dialer.User + ":" + dialer.Password),
49+
)
50+
connectReq += fmt.Sprintf("Proxy-Authorization: Basic %s\r\n", auth)
51+
}
52+
connectReq += "Connection: keep-alive\r\n\r\n"
53+
if _, err := conn.Write([]byte(connectReq)); err != nil {
54+
conn.Close()
55+
return nil, err
56+
}
57+
reader := bufio.NewReader(conn)
58+
response, err := reader.ReadString('\n')
59+
if err != nil {
60+
conn.Close()
61+
return nil, err
62+
}
63+
if !strings.HasPrefix(response, "HTTP/1.1 200") &&
64+
!strings.HasPrefix(response, "HTTP/1.0 200") {
65+
conn.Close()
66+
return nil, fmt.Errorf("proxy connection failed: %s", strings.TrimSpace(response))
67+
}
68+
for {
69+
line, err := reader.ReadString('\n')
70+
if err != nil {
71+
conn.Close()
72+
return nil, err
73+
}
74+
if line == "\r\n" || line == "\n" {
75+
break
76+
}
77+
}
78+
conn.SetDeadline(time.Time{})
79+
80+
return conn, nil
81+
}

core/utils/ssh/ssh.go

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,23 @@ import (
88
"strings"
99
"time"
1010

11+
"github.com/1Panel-dev/1Panel/core/app/repo"
1112
"github.com/1Panel-dev/1Panel/core/global"
13+
"github.com/1Panel-dev/1Panel/core/utils/encrypt"
1214
gossh "golang.org/x/crypto/ssh"
15+
"golang.org/x/net/proxy"
1316
)
1417

1518
type ConnInfo struct {
16-
User string `json:"user"`
17-
Addr string `json:"addr"`
18-
Port int `json:"port"`
19-
AuthMode string `json:"authMode"`
20-
Password string `json:"password"`
21-
PrivateKey []byte `json:"privateKey"`
22-
PassPhrase []byte `json:"passPhrase"`
19+
User string `json:"user"`
20+
Addr string `json:"addr"`
21+
Port int `json:"port"`
22+
AuthMode string `json:"authMode"`
23+
Password string `json:"password"`
24+
PrivateKey []byte `json:"privateKey"`
25+
PassPhrase []byte `json:"passPhrase"`
26+
27+
UseProxy bool `json:"useProxy"`
2328
DialTimeOut time.Duration `json:"dialTimeOut"`
2429
}
2530

@@ -52,7 +57,7 @@ func NewClient(c ConnInfo) (*SSHClient, error) {
5257
if strings.Contains(c.Addr, ":") {
5358
proto = "tcp6"
5459
}
55-
client, err := DialWithTimeout(proto, addr, config)
60+
client, err := DialWithTimeout(proto, addr, c.UseProxy, config)
5661
if nil != err {
5762
return nil, err
5863
}
@@ -240,8 +245,14 @@ func (c *SSHClient) RunWithStreamOutput(command string, outputCallback func(stri
240245
return err
241246
}
242247

243-
func DialWithTimeout(network, addr string, config *gossh.ClientConfig) (*gossh.Client, error) {
244-
conn, err := net.DialTimeout(network, addr, config.Timeout)
248+
func DialWithTimeout(network, addr string, useProxy bool, config *gossh.ClientConfig) (*gossh.Client, error) {
249+
var conn net.Conn
250+
var err error
251+
if useProxy {
252+
conn, err = loadSSHConnByProxy(network, addr, config.Timeout)
253+
} else {
254+
conn, err = net.DialTimeout(network, addr, config.Timeout)
255+
}
245256
if err != nil {
246257
return nil, err
247258
}
@@ -256,3 +267,55 @@ func DialWithTimeout(network, addr string, config *gossh.ClientConfig) (*gossh.C
256267
}
257268
return gossh.NewClient(c, chans, reqs), nil
258269
}
270+
271+
func loadSSHConnByProxy(network, addr string, timeout time.Duration) (net.Conn, error) {
272+
settingRepo := repo.NewISettingRepo()
273+
proxyType, err := settingRepo.Get(repo.WithByKey("ProxyType"))
274+
if err != nil {
275+
return nil, fmt.Errorf("get proxy type from db failed, err: %v", err)
276+
}
277+
if len(proxyType.Value) == 0 {
278+
return nil, fmt.Errorf("get proxy type from db failed, err: %v", err)
279+
}
280+
proxyUrl, _ := settingRepo.Get(repo.WithByKey("ProxyUrl"))
281+
port, _ := settingRepo.Get(repo.WithByKey("ProxyPort"))
282+
user, _ := settingRepo.Get(repo.WithByKey("ProxyUser"))
283+
passwd, _ := settingRepo.Get(repo.WithByKey("ProxyPasswd"))
284+
285+
pass, _ := encrypt.StringDecrypt(passwd.Value)
286+
proxyItem := fmt.Sprintf("%s:%s", proxyUrl.Value, port.Value)
287+
switch proxyType.Value {
288+
case "http", "https":
289+
item := HTTPProxyDialer{
290+
Type: proxyType.Value,
291+
URL: proxyItem,
292+
User: user.Value,
293+
Password: pass,
294+
}
295+
return HTTPDial(item, network, addr)
296+
case "socks5":
297+
var auth *proxy.Auth
298+
if len(user.Value) == 0 {
299+
auth = nil
300+
} else {
301+
auth = &proxy.Auth{
302+
User: user.Value,
303+
Password: pass,
304+
}
305+
}
306+
dialer, err := proxy.SOCKS5("tcp", proxyItem, auth, &net.Dialer{
307+
Timeout: 30 * time.Second,
308+
KeepAlive: 30 * time.Second,
309+
})
310+
if err != nil {
311+
return nil, fmt.Errorf("new socks5 proxy failed, err: %v", err)
312+
}
313+
return dialer.Dial(network, addr)
314+
default:
315+
conn, err := net.DialTimeout(network, addr, timeout)
316+
if err != nil {
317+
return nil, err
318+
}
319+
return conn, nil
320+
}
321+
}

0 commit comments

Comments
 (0)