-
Notifications
You must be signed in to change notification settings - Fork 0
/
config.go
175 lines (149 loc) · 5.08 KB
/
config.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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
package config
import (
"encoding/json"
"errors"
"fmt"
"os"
)
// LoadJSON load config from bytes in JSON format
func LoadJSON(bs []byte) (*Config, error) {
conf := new(Config)
err := json.Unmarshal(bs, conf)
return conf, err
}
// LoadFile load config from JSON file
func LoadFile(filename string) (*Config, error) {
bs, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
return LoadJSON(bs)
}
type Config struct {
Inbounds Inbounds `json:"inbounds,omitempty"` // 入站代理
Outbounds []*YeagerClient `json:"outbounds,omitempty"` // 出站代理
Rules []string `json:"rules,omitempty"` // 路由规则
Develop bool `json:"develop,omitempty"` // developer only
}
type Inbounds struct {
SOCKS *SOCKSProxy `json:"socks,omitempty"`
HTTP *HTTPProxy `json:"http,omitempty"`
Yeager *YeagerServer `json:"yeager,omitempty"`
}
type SOCKSProxy struct {
Listen string `json:"listen"`
}
type HTTPProxy struct {
Listen string `json:"listen"`
}
type Transport string
const (
TransTCP Transport = "tcp"
TransGRPC Transport = "grpc"
TransQUIC Transport = "quic"
)
type ServerSecurityType string
const (
NoSecurity ServerSecurityType = "" // no security, means plaintext
TLS ServerSecurityType = "tls" // security by TLS, manage certificate manually
TLSAcme ServerSecurityType = "tls-acme" // security by TLS, manage certificate automatically
TLSMutual ServerSecurityType = "tls-mutual" // security by mutual TLS
)
type Tls struct {
CertFile string `json:"certFile"`
CertPEM []byte `json:"-"`
KeyFile string `json:"keyFile"`
KeyPEM []byte `json:"-"`
}
type Acme struct {
Domain string `json:"domain"`
}
type Mtls struct {
CertFile string `json:"certFile"`
CertPEM []byte `json:"-"`
KeyFile string `json:"keyFile"`
KeyPEM []byte `json:"-"`
ClientCAFile string `json:"clientCAFile"`
ClientCA []byte `json:"-"`
}
type YeagerServer struct {
Listen string `json:"listen"`
UUID string `json:"uuid"` // ignored when Security is TLSMutual
Transport Transport `json:"transport"`
Security ServerSecurityType `json:"security"`
TLS Tls `json:"tls,omitempty"` // available when Security is TLS
ACME Acme `json:"acme,omitempty"` // available when Security is TLSAcme
MTLS Mtls `json:"mtls,omitempty"` // available when Security is TLSMutual
}
type ClientSecurityType string
const (
ClientNoSecurity ClientSecurityType = "" // no security, means plaintext
ClientTLS ClientSecurityType = "tls" // security by TLS, manage certificate manually
ClientTLSMutual ClientSecurityType = "tls-mutual" // security by mutual TLS
)
type ClientTls struct {
Insecure bool `json:"insecure,omitempty"` // allow insecure
}
type ClientMTLS struct {
CertFile string `json:"certFile"`
CertPEM []byte `json:"-"`
KeyFile string `json:"keyFile"`
KeyPEM []byte `json:"-"`
RootCAFile string `json:"rootCAFile"`
RootCA []byte `json:"-"`
}
type YeagerClient struct {
Tag string `json:"tag"` // 出站标记,用于路由规则指定出站代理
Address string `json:"address"`
UUID string `json:"uuid"` // ignored when Security is TLSMutual
Transport Transport `json:"transport"`
Security ClientSecurityType `json:"security"`
TLS ClientTls `json:"tls,omitempty"` // available when Security is ClientTLS
MTLS ClientMTLS `json:"mtls,omitempty"` // available when Security is ClientTLSMutual
}
const (
EnvYeagerAddress = "YEAGER_ADDRESS"
EnvYeagerUUID = "YEAGER_UUID"
EnvYeagerTransport = "YEAGER_TRANSPORT"
EnvYeagerDomain = "YEAGER_DOMAIN"
EnvYeagerSecurity = "YEAGER_SECURITY"
)
// LoadEnv generate configuration from environment variables,
// suitable for server side plaintext or TLS with ACME
func LoadEnv() (conf *Config, err error, foundEnv bool) {
address, foundAddr := os.LookupEnv(EnvYeagerAddress)
uuid, foundUUID := os.LookupEnv(EnvYeagerUUID)
transport, foundTransport := os.LookupEnv(EnvYeagerTransport)
domain, foundDomain := os.LookupEnv(EnvYeagerDomain)
if foundAddr || foundUUID || foundTransport || foundDomain == false {
return nil, nil, false
}
foundEnv = true
if address == "" {
return nil, fmt.Errorf("required env %s", EnvYeagerAddress), foundEnv
}
if uuid == "" {
return nil, fmt.Errorf("required env %s", EnvYeagerUUID), foundEnv
}
if transport == "" {
return nil, fmt.Errorf("required env %s", EnvYeagerTransport), foundEnv
}
if domain == "" {
return nil, fmt.Errorf("required env %s", EnvYeagerDomain), foundEnv
}
security := os.Getenv(EnvYeagerSecurity)
sc := &YeagerServer{
Listen: address,
UUID: uuid,
Transport: Transport(transport),
Security: ServerSecurityType(security),
}
switch sc.Security {
case NoSecurity:
case TLSAcme:
sc.ACME = Acme{Domain: domain}
default:
return nil, errors.New("LoadEnv does not support security: " + security), foundEnv
}
return &Config{Inbounds: Inbounds{Yeager: sc}}, nil, foundEnv
}