-
Notifications
You must be signed in to change notification settings - Fork 34
/
backend.go
111 lines (91 loc) · 2.7 KB
/
backend.go
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
/**
* File: backend.go
* Author: Ming Cheng<[email protected]>
*
* Created Date: Tuesday, June 21st 2022, 6:03:26 pm
* Last Modified: Thursday, July 7th 2022, 6:30:08 pm
*
* http://www.opensource.org/licenses/MIT
*/
package socks5lb
import (
log "github.com/sirupsen/logrus"
"golang.org/x/net/context"
"net"
"net/http"
"time"
"github.com/txthinking/socks5"
)
type BackendCheckConfig struct {
CheckURL string `yaml:"check_url" json:"check_url"`
InitialAlive bool `yaml:"initial_alive" json:"initial_alive"`
Timeout uint `yaml:"timeout" json:"timeout"`
}
type Backend struct {
Addr string `yaml:"addr" json:"addr" binding:"required"`
UserName string `yaml:"username" json:"username"`
Password string `yaml:"password" json:"password"`
CheckConfig BackendCheckConfig `yaml:"check_config" json:"check_config"`
alive bool
}
// Alive returns backend status
func (b *Backend) Alive() bool {
return b.alive
}
// Check function to check the node healthy by given url
func (b *Backend) Check() (err error) {
if url := b.CheckConfig.CheckURL; url != "" {
var (
client *http.Client
resp *http.Response
)
if client, err = b.httpProxyClient(); err != nil {
return
}
resp, err = client.Head(url)
if err != nil || (resp != nil && resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusMovedPermanently && resp.StatusCode != http.StatusFound) {
log.Error(err)
b.alive = false
} else {
b.alive = true
}
return
}
b.alive = b.CheckConfig.InitialAlive
return
}
// httpProxyClient to create http client with socks5 proxy
func (b *Backend) httpProxyClient() (*http.Client, error) {
var timeout = b.CheckConfig.Timeout
// setup a http client
httpTransport := &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
return b.Socks5Conn("tcp", addr, int(timeout))
},
}
return &http.Client{
Transport: httpTransport,
Timeout: time.Duration(timeout) * time.Second,
}, nil
}
// socks5Client to create http client with socks5 proxy
func (b *Backend) socks5Client(timeout int) (*socks5.Client, error) {
return socks5.NewClient(string(b.Addr), b.UserName, b.Password, timeout, timeout)
}
// Socks5Conn to create a connection by specific params
func (b *Backend) Socks5Conn(network, addr string, timeout int) (cc net.Conn, err error) {
client, err := b.socks5Client(timeout)
if err != nil {
return
}
return client.Dial(network, addr)
}
// NewBackend creates a new Backend instance
func NewBackend(addr string, config BackendCheckConfig) (backend *Backend) {
backend = &Backend{
Addr: addr,
alive: config.InitialAlive,
CheckConfig: config,
}
return
}