summaryrefslogtreecommitdiff
path: root/internal/config/outbounds.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/config/outbounds.go')
-rw-r--r--internal/config/outbounds.go212
1 files changed, 212 insertions, 0 deletions
diff --git a/internal/config/outbounds.go b/internal/config/outbounds.go
new file mode 100644
index 0000000..582b625
--- /dev/null
+++ b/internal/config/outbounds.go
@@ -0,0 +1,212 @@
+package config
+
+import "vpnem/internal/models"
+
+type InboundConfig map[string]any
+
+func BuildOutbound(server models.Server) map[string]any {
+ return BuildOutboundWithTag(server, "proxy")
+}
+
+func BuildOutboundWithTag(server models.Server, tag string) map[string]any {
+ switch server.Type {
+ case "vless":
+ return buildVLESSOutbound(server, tag)
+ case "vless-reality":
+ return buildVLESSRealityOutbound(server, tag)
+ case "vmess":
+ return buildVMessOutbound(server, tag)
+ case "shadowsocks":
+ return buildShadowsocksOutbound(server, tag)
+ case "hysteria2":
+ return buildHysteria2Outbound(server, tag)
+ default:
+ return buildSOCKSOutbound(server, tag)
+ }
+}
+
+func BuildHysteria2Inbound(_ any, port int, password string, obfsPassword string, upMbps int, downMbps int, certPath string, keyPath string) (*InboundConfig, error) {
+ if password == "" {
+ return nil, errConfig("hysteria2 inbound requires password")
+ }
+ if certPath == "" || keyPath == "" {
+ return nil, errConfig("hysteria2 inbound requires certificate and key paths")
+ }
+ inbound := InboundConfig{
+ "type": "hysteria2",
+ "tag": "hysteria2-in",
+ "listen": "::",
+ "listen_port": port,
+ "users": []map[string]any{
+ {"name": "user-01", "password": password},
+ },
+ "tls": map[string]any{
+ "enabled": true,
+ "alpn": []string{"h3"},
+ "min_version": "1.3",
+ "max_version": "1.3",
+ "certificate_path": certPath,
+ "key_path": keyPath,
+ },
+ }
+ if upMbps > 0 {
+ inbound["up_mbps"] = upMbps
+ }
+ if downMbps > 0 {
+ inbound["down_mbps"] = downMbps
+ }
+ if obfsPassword != "" {
+ inbound["obfs"] = map[string]any{
+ "type": "salamander",
+ "password": obfsPassword,
+ }
+ }
+ return &inbound, nil
+}
+
+func buildVLESSOutbound(server models.Server, tag string) map[string]any {
+ outbound := map[string]any{
+ "type": "vless", "tag": tag,
+ "server": server.Server, "server_port": server.ServerPort, "uuid": server.UUID,
+ }
+ applyTLS(outbound, server.TLS)
+ applyTransport(outbound, server.Transport)
+ return outbound
+}
+
+func buildVLESSRealityOutbound(server models.Server, tag string) map[string]any {
+ outbound := map[string]any{
+ "type": "vless", "tag": tag,
+ "server": server.Server, "server_port": server.ServerPort, "uuid": server.UUID,
+ }
+ applyTLS(outbound, server.TLS)
+ return outbound
+}
+
+func buildVMessOutbound(server models.Server, tag string) map[string]any {
+ outbound := map[string]any{
+ "type": "vmess", "tag": tag,
+ "server": server.Server, "server_port": server.ServerPort,
+ "uuid": server.UUID, "security": "auto", "alter_id": 0,
+ }
+ applyTLS(outbound, server.TLS)
+ applyTransport(outbound, server.Transport)
+ return outbound
+}
+
+func buildShadowsocksOutbound(server models.Server, tag string) map[string]any {
+ return map[string]any{
+ "type": "shadowsocks", "tag": tag,
+ "server": server.Server, "server_port": server.ServerPort,
+ "method": server.Method, "password": server.Password,
+ }
+}
+
+func buildHysteria2Outbound(server models.Server, tag string) map[string]any {
+ outbound := map[string]any{
+ "type": "hysteria2", "tag": tag,
+ "server": server.Server, "server_port": server.ServerPort,
+ "password": server.Password,
+ }
+ if server.UpMbps > 0 {
+ outbound["up_mbps"] = server.UpMbps
+ }
+ if server.DownMbps > 0 {
+ outbound["down_mbps"] = server.DownMbps
+ }
+ if server.ObfsPassword != "" {
+ outbound["obfs"] = map[string]any{"type": "salamander", "password": server.ObfsPassword}
+ }
+ tlsConfig := map[string]any{
+ "enabled": true,
+ "insecure": true,
+ "alpn": []string{"h3"},
+ "min_version": "1.3",
+ "max_version": "1.3",
+ }
+ if server.TLS != nil {
+ if server.TLS.ServerName != "" {
+ tlsConfig["server_name"] = server.TLS.ServerName
+ }
+ if len(server.TLS.ALPN) > 0 {
+ tlsConfig["alpn"] = server.TLS.ALPN
+ }
+ if server.TLS.MinVersion != "" {
+ tlsConfig["min_version"] = server.TLS.MinVersion
+ }
+ if server.TLS.MaxVersion != "" {
+ tlsConfig["max_version"] = server.TLS.MaxVersion
+ }
+ if server.TLS.Insecure {
+ tlsConfig["insecure"] = true
+ }
+ }
+ outbound["tls"] = tlsConfig
+ return outbound
+}
+
+func buildSOCKSOutbound(server models.Server, tag string) map[string]any {
+ return map[string]any{
+ "type": "socks", "tag": tag,
+ "server": server.Server, "server_port": server.ServerPort,
+ "udp_over_tcp": server.UDPOverTCP,
+ }
+}
+
+func applyTLS(outbound map[string]any, tls *models.TLS) {
+ if tls == nil {
+ return
+ }
+ tlsConfig := map[string]any{
+ "enabled": tls.Enabled,
+ "server_name": tls.ServerName,
+ }
+ if tls.Insecure {
+ tlsConfig["insecure"] = true
+ }
+ if len(tls.ALPN) > 0 {
+ tlsConfig["alpn"] = tls.ALPN
+ }
+ if tls.MinVersion != "" {
+ tlsConfig["min_version"] = tls.MinVersion
+ }
+ if tls.MaxVersion != "" {
+ tlsConfig["max_version"] = tls.MaxVersion
+ }
+ if tls.Reality != nil && tls.Reality.Enabled {
+ tlsConfig["reality"] = map[string]any{
+ "enabled": true,
+ "public_key": tls.Reality.PublicKey,
+ "short_id": tls.Reality.ShortID,
+ }
+ if tls.Reality.Fingerprint != "" {
+ tlsConfig["utls"] = map[string]any{
+ "enabled": true,
+ "fingerprint": tls.Reality.Fingerprint,
+ }
+ }
+ }
+ outbound["tls"] = tlsConfig
+}
+
+func errConfig(message string) error {
+ return &configError{message: message}
+}
+
+type configError struct {
+ message string
+}
+
+func (e *configError) Error() string {
+ return e.message
+}
+
+func applyTransport(outbound map[string]any, transport *models.Transport) {
+ if transport == nil {
+ return
+ }
+ outbound["transport"] = map[string]any{
+ "type": transport.Type,
+ "path": transport.Path,
+ }
+}