init commit
This commit is contained in:
156
core/singbox_config.go
Normal file
156
core/singbox_config.go
Normal file
@@ -0,0 +1,156 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
// GenerateSingBoxConfig generates a full JSON config for sing-box (v1.14+).
|
||||
// sing-box acts as frontend: creates a TUN interface,
|
||||
// captures system traffic and routes it to xray via SOCKS5.
|
||||
func GenerateSingBoxConfig(serverAddress string, socksPort int, tunName string) (string, error) {
|
||||
if socksPort == 0 {
|
||||
socksPort = DefaultSocksPort
|
||||
}
|
||||
if tunName == "" {
|
||||
tunName = "kettuTun"
|
||||
}
|
||||
|
||||
config := map[string]any{
|
||||
"log": buildSingBoxLog(),
|
||||
"dns": buildSingBoxDns(),
|
||||
"inbounds": []any{buildTunInbound(tunName)},
|
||||
"outbounds": buildSingBoxOutbounds(socksPort),
|
||||
"route": buildSingBoxRoute(serverAddress),
|
||||
}
|
||||
|
||||
data, err := json.MarshalIndent(config, "", " ")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to marshal sing-box config: %w", err)
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
func buildSingBoxLog() map[string]any {
|
||||
return map[string]any{
|
||||
"level": "info",
|
||||
"timestamp": true,
|
||||
}
|
||||
}
|
||||
|
||||
func buildSingBoxDns() map[string]any {
|
||||
return map[string]any{
|
||||
"servers": []any{
|
||||
map[string]any{
|
||||
"type": "https",
|
||||
"tag": "remote-dns",
|
||||
"server": "1.1.1.1",
|
||||
"server_port": 443,
|
||||
"path": "/dns-query",
|
||||
"detour": "proxy-out",
|
||||
},
|
||||
map[string]any{
|
||||
"type": "https",
|
||||
"tag": "local-dns",
|
||||
"server": "8.8.8.8",
|
||||
"server_port": 443,
|
||||
"path": "/dns-query",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func buildTunInbound(tunName string) map[string]any {
|
||||
tun := map[string]any{
|
||||
"type": "tun",
|
||||
"tag": "tun-in",
|
||||
"address": []string{
|
||||
"172.18.0.1/30",
|
||||
"fdfe:dcba:9876::1/126",
|
||||
},
|
||||
"mtu": 1400,
|
||||
"auto_route": true,
|
||||
"strict_route": false,
|
||||
"stack": "gvisor",
|
||||
}
|
||||
|
||||
if tunName != "" && tunName != "kettuTun" {
|
||||
tun["interface_name"] = tunName
|
||||
}
|
||||
|
||||
return tun
|
||||
}
|
||||
|
||||
func buildSingBoxOutbounds(socksPort int) []any {
|
||||
return []any{
|
||||
map[string]any{
|
||||
"type": "socks",
|
||||
"tag": "proxy-out",
|
||||
"server": "127.0.0.1",
|
||||
"server_port": socksPort,
|
||||
"version": "5",
|
||||
"udp_over_tcp": false,
|
||||
},
|
||||
map[string]any{
|
||||
"type": "direct",
|
||||
"tag": "direct-out",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func buildSingBoxRoute(serverAddress string) map[string]any {
|
||||
rules := []any{
|
||||
// Anti routing loop: bypass VPN core processes
|
||||
map[string]any{
|
||||
"process_name": []string{"xray.exe", "sing-box.exe", "kettuRay.exe"},
|
||||
"action": "route",
|
||||
"outbound": "direct-out",
|
||||
},
|
||||
}
|
||||
|
||||
// Anti routing loop: bypass remote VPN server
|
||||
bypassRule := map[string]any{
|
||||
"action": "route",
|
||||
"outbound": "direct-out",
|
||||
}
|
||||
|
||||
if ip := net.ParseIP(serverAddress); ip != nil {
|
||||
prefix := "32"
|
||||
if ip.To4() == nil {
|
||||
prefix = "128"
|
||||
}
|
||||
bypassRule["ip_cidr"] = []string{serverAddress + "/" + prefix}
|
||||
} else {
|
||||
bypassRule["domain"] = []string{serverAddress}
|
||||
}
|
||||
rules = append(rules, bypassRule)
|
||||
|
||||
// Sniff rule
|
||||
rules = append(rules, map[string]any{
|
||||
"action": "sniff",
|
||||
"timeout": "300ms",
|
||||
})
|
||||
|
||||
// DNS hijack
|
||||
rules = append(rules, map[string]any{
|
||||
"protocol": "dns",
|
||||
"action": "hijack-dns",
|
||||
})
|
||||
|
||||
// Private IPs go direct
|
||||
rules = append(rules, map[string]any{
|
||||
"ip_is_private": true,
|
||||
"action": "route",
|
||||
"outbound": "direct-out",
|
||||
})
|
||||
|
||||
return map[string]any{
|
||||
"rules": rules,
|
||||
"default_domain_resolver": map[string]any{
|
||||
"server": "local-dns",
|
||||
},
|
||||
"final": "proxy-out",
|
||||
"auto_detect_interface": true,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user