From eeb6a34b0333be7fa86ea0ad41bcffdd045dff66 Mon Sep 17 00:00:00 2001 From: dnomd343 Date: Wed, 17 Aug 2022 20:46:43 +0800 Subject: [PATCH] refactor: split into multi packages --- cmd/asset/geofile.go | 25 ++++ cmd/asset/update.go | 15 +++ cmd/common/file.go | 94 ++++++++++++++ cmd/common/net.go | 22 ++++ cmd/common/sys.go | 19 +++ cmd/network/dns.go | 19 +++ cmd/network/main.go | 18 +++ cmd/network/network.go | 51 ++++++++ cmd/network/tproxy.go | 47 +++++++ cmd/proxy/config.go | 84 ++++++++++++ cmd/proxy/load.go | 65 ++++++++++ cmd/proxy/object.go | 37 ++++++ main.go | 19 +++ src/config.go | 18 --- src/load.go | 286 ----------------------------------------- src/network.go | 98 -------------- 16 files changed, 515 insertions(+), 402 deletions(-) create mode 100644 cmd/asset/geofile.go create mode 100644 cmd/asset/update.go create mode 100644 cmd/common/file.go create mode 100644 cmd/common/net.go create mode 100644 cmd/common/sys.go create mode 100644 cmd/network/dns.go create mode 100644 cmd/network/main.go create mode 100644 cmd/network/network.go create mode 100644 cmd/network/tproxy.go create mode 100644 cmd/proxy/config.go create mode 100644 cmd/proxy/load.go create mode 100644 cmd/proxy/object.go create mode 100644 main.go delete mode 100644 src/load.go delete mode 100644 src/network.go diff --git a/cmd/asset/geofile.go b/cmd/asset/geofile.go new file mode 100644 index 0000000..1a0db34 --- /dev/null +++ b/cmd/asset/geofile.go @@ -0,0 +1,25 @@ +package asset + +import ( + "XProxy/cmd/common" + log "github.com/sirupsen/logrus" +) + +func extractGeoFile(archivePath string, geoFile string, targetDir string) { + if common.IsFileExist(targetDir + "/" + geoFile) { + log.Debugf("Asset %s exist -> skip extract", geoFile) + return + } + log.Infof("Extract asset file -> %s", targetDir+"/"+geoFile) + common.RunCommand("tar", "xvf", archivePath, "./"+geoFile, "-C", targetDir) +} + +func LoadGeoIp(assetFile string, assetDir string) { + common.CreateFolder(assetDir) + extractGeoFile(assetFile, "geoip.dat", assetDir) +} + +func LoadGeoSite(assetFile string, assetDir string) { + common.CreateFolder(assetDir) + extractGeoFile(assetFile, "geosite.dat", assetDir) +} diff --git a/cmd/asset/update.go b/cmd/asset/update.go new file mode 100644 index 0000000..cb70172 --- /dev/null +++ b/cmd/asset/update.go @@ -0,0 +1,15 @@ +package asset + +import ( + "XProxy/cmd/common" + log "github.com/sirupsen/logrus" +) + +func UpdateAssets(urls map[string]string, assetDir string) { + if len(urls) != 0 { + log.Info("Start update assets") + for file, url := range urls { + common.DownloadFile(url, assetDir+"/"+file) + } + } +} diff --git a/cmd/common/file.go b/cmd/common/file.go new file mode 100644 index 0000000..7d7907e --- /dev/null +++ b/cmd/common/file.go @@ -0,0 +1,94 @@ +package common + +import ( + log "github.com/sirupsen/logrus" + "io" + "io/ioutil" + "net/http" + "os" + "strings" +) + +func CreateFolder(folderPath string) { + log.Debugf("Create folder -> %s", folderPath) + err := os.MkdirAll(folderPath, 0755) + if err != nil { + log.Panicf("Failed to create folder -> %s", folderPath) + } +} + +func IsFileExist(filePath string) bool { + s, err := os.Stat(filePath) + if err != nil { // file or folder not exist + return false + } + return !s.IsDir() +} + +func WriteFile(filePath string, content string, overwrite bool) { + if !overwrite && IsFileExist(filePath) { // file exist and don't overwrite + log.Debugf("File `%s` exist -> skip write", filePath) + return + } + log.Debugf("Write file `%s` -> \n%s", filePath, content) + err := os.WriteFile(filePath, []byte(content), 0644) + if err != nil { + log.Panicf("Failed to write `%s` -> %v", filePath, err) + } +} + +func ListFiles(folderPath string, suffix string) []string { + var fileList []string + files, err := ioutil.ReadDir(folderPath) + if err != nil { + log.Panicf("Failed to list folder -> %s", folderPath) + } + for _, file := range files { + if strings.HasSuffix(file.Name(), suffix) { + fileList = append(fileList, file.Name()) + } + } + return fileList +} + +func CopyFile(source string, target string) { + log.Infof("Copy file `%s` => `%s`", source, target) + if IsFileExist(target) { + log.Warningf("File `%s` will be overrided", target) + } + srcFile, err := os.Open(source) + if err != nil { + log.Panicf("Failed to open file -> %s", source) + } + dstFile, err := os.OpenFile(target, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644) + if err != nil { + _ = srcFile.Close() + log.Panicf("Failed to open file -> %s", target) + } + _, err = io.Copy(dstFile, srcFile) + _ = srcFile.Close() + _ = dstFile.Close() + if err != nil { + log.Panicf("Failed to copy from `%s` to `%s`", source, target) + } +} + +func DownloadFile(url string, file string) { + log.Debugf("File download `%s` => `%s`", url, file) + resp, err := http.Get(url) + if err != nil { + log.Errorf("Download `%s` error -> %v", url, err) + return + } + out, err := os.OpenFile(file, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644) + if err != nil { + _ = resp.Body.Close() + log.Panicf("Open `%s` error -> %v", file, err) + } + _, err = io.Copy(out, resp.Body) + _ = resp.Body.Close() + if err != nil { + log.Panicf("File `%s` save error -> %v", file, err) + } + log.Infof("Download success `%s` => `%s`", url, file) +} diff --git a/cmd/common/net.go b/cmd/common/net.go new file mode 100644 index 0000000..7ac05da --- /dev/null +++ b/cmd/common/net.go @@ -0,0 +1,22 @@ +package common + +import ( + "net" + "strings" +) + +func isIP(ipAddr string, isCidr bool) bool { + if !isCidr { + return net.ParseIP(ipAddr) != nil + } + _, _, err := net.ParseCIDR(ipAddr) + return err == nil +} + +func IsIPv4(ipAddr string, isCidr bool) bool { + return isIP(ipAddr, isCidr) && strings.Contains(ipAddr, ".") +} + +func IsIPv6(ipAddr string, isCidr bool) bool { + return isIP(ipAddr, isCidr) && strings.Contains(ipAddr, ":") +} diff --git a/cmd/common/sys.go b/cmd/common/sys.go new file mode 100644 index 0000000..b25c3d7 --- /dev/null +++ b/cmd/common/sys.go @@ -0,0 +1,19 @@ +package common + +import ( + log "github.com/sirupsen/logrus" + "os/exec" + "syscall" +) + +func RunCommand(command ...string) (int, string) { + log.Debugf("Running system command -> %v", command) + process := exec.Command(command[0], command[1:]...) + output, _ := process.CombinedOutput() + log.Debugf("Command %v -> \n%s", command, string(output)) + code := process.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() + if code != 0 { + log.Warningf("Command %v return code %d", command, code) + } + return code, string(output) +} diff --git a/cmd/network/dns.go b/cmd/network/dns.go new file mode 100644 index 0000000..43c2ee2 --- /dev/null +++ b/cmd/network/dns.go @@ -0,0 +1,19 @@ +package network + +import ( + "XProxy/cmd/common" + log "github.com/sirupsen/logrus" +) + +func loadDns(dnsServer []string) { + if len(dnsServer) == 0 { + log.Info("Using system DNS server") + return + } + log.Infof("Setting up DNS server -> %v", dnsServer) + dnsConfig := "" + for _, address := range dnsServer { + dnsConfig += "nameserver " + address + "\n" + } + common.WriteFile("/etc/resolv.conf", dnsConfig, true) +} diff --git a/cmd/network/main.go b/cmd/network/main.go new file mode 100644 index 0000000..2c0be50 --- /dev/null +++ b/cmd/network/main.go @@ -0,0 +1,18 @@ +package network + +type Config struct { + IPv4 struct { + Address string + Gateway string + RouteTable int + TProxyPort int + } + V4RouteTable int + V6RouteTable int + V4TProxyPort int + V6TProxyPort int +} + +func Load() { + +} diff --git a/cmd/network/network.go b/cmd/network/network.go new file mode 100644 index 0000000..68d7cd1 --- /dev/null +++ b/cmd/network/network.go @@ -0,0 +1,51 @@ +package network + +import ( + "XProxy/cmd/common" + log "github.com/sirupsen/logrus" + "regexp" +) + +func getV4Cidr() []string { + var v4Cidr []string + _, output := common.RunCommand("ip", "-4", "addr") + for _, temp := range regexp.MustCompile(`inet (\S+)`).FindAllStringSubmatch(output, -1) { + v4Cidr = append(v4Cidr, temp[1]) + } + return v4Cidr +} + +func getV6Cidr() []string { + var v6Cidr []string + _, output := common.RunCommand("ip", "-6", "addr") + for _, temp := range regexp.MustCompile(`inet6 (\S+)`).FindAllStringSubmatch(output, -1) { + v6Cidr = append(v6Cidr, temp[1]) + } + return v6Cidr +} + +func loadNetwork(v4Address string, v4Gateway string, v6Address string, v6Gateway string) { + log.Info("Enabled IP forward") + common.RunCommand("sysctl", "-w", "net.ipv4.ip_forward=1") + common.RunCommand("sysctl", "-w", "net.ipv6.conf.all.forwarding=1") + + log.Info("Flush system IP configure") + common.RunCommand("ip", "link", "set", "eth0", "down") + common.RunCommand("ip", "-4", "addr", "flush", "dev", "eth0") + common.RunCommand("ip", "-6", "addr", "flush", "dev", "eth0") + common.RunCommand("ip", "link", "set", "eth0", "down") + + log.Info("Setting up system IP configure") + if v4Address != "" { + common.RunCommand("ip", "-4", "addr", "add", v4Address, "dev", "eth0") + } + if v4Gateway != "" { + common.RunCommand("ip", "-4", "route", "add", "default", "via", v4Gateway) + } + if v6Address != "" { + common.RunCommand("ip", "-6", "addr", "add", v6Address, "dev", "eth0") + } + if v6Gateway != "" { + common.RunCommand("ip", "-6", "route", "add", "default", "via", v6Gateway) + } +} diff --git a/cmd/network/tproxy.go b/cmd/network/tproxy.go new file mode 100644 index 0000000..e6732b6 --- /dev/null +++ b/cmd/network/tproxy.go @@ -0,0 +1,47 @@ +package network + +import ( + "XProxy/cmd/common" + log "github.com/sirupsen/logrus" + "strconv" +) + +type tproxyConfig struct { + routeTable int + tproxyPort int + bypassCidr []string +} + +func loadV4TProxy(config tproxyConfig) { + log.Info("Setting up TProxy of IPv4") + tableNum := strconv.Itoa(config.routeTable) + common.RunCommand("ip", "-4", "rule", "add", "fwmark", "1", "table", tableNum) + common.RunCommand("ip", "-4", "route", "add", "local", "0.0.0.0/0", "dev", "lo", "table", tableNum) + common.RunCommand("iptables", "-t", "mangle", "-N", "XPROXY") + log.Infof("Setting up IPv4 bypass CIDR -> %v", config.bypassCidr) + for _, cidr := range config.bypassCidr { + common.RunCommand("iptables", "-t", "mangle", "-A", "XPROXY", "-d", cidr, "-j", "RETURN") + } + common.RunCommand("iptables", "-t", "mangle", "-A", "XPROXY", + "-p", "tcp", "-j", "TPROXY", "--on-port", strconv.Itoa(config.tproxyPort), "--tproxy-mark", "1") + common.RunCommand("iptables", "-t", "mangle", "-A", "XPROXY", + "-p", "udp", "-j", "TPROXY", "--on-port", strconv.Itoa(config.tproxyPort), "--tproxy-mark", "1") + common.RunCommand("iptables", "-t", "mangle", "-A", "PREROUTING", "-j", "XPROXY") +} + +func loadV6TProxy(config tproxyConfig) { + log.Info("Setting up TProxy of IPv6") + tableNum := strconv.Itoa(config.routeTable) + common.RunCommand("ip", "-6", "rule", "add", "fwmark", "1", "table", tableNum) + common.RunCommand("ip", "-6", "route", "add", "local", "::/0", "dev", "lo", "table", tableNum) + common.RunCommand("ip6tables", "-t", "mangle", "-N", "XPROXY6") + log.Infof("Setting up IPv6 bypass CIDR -> %v", config.bypassCidr) + for _, cidr := range config.bypassCidr { + common.RunCommand("ip6tables", "-t", "mangle", "-A", "XPROXY6", "-d", cidr, "-j", "RETURN") + } + common.RunCommand("ip6tables", "-t", "mangle", "-A", "XPROXY6", + "-p", "tcp", "-j", "TPROXY", "--on-port", strconv.Itoa(config.tproxyPort), "--tproxy-mark", "1") + common.RunCommand("ip6tables", "-t", "mangle", "-A", "XPROXY6", + "-p", "udp", "-j", "TPROXY", "--on-port", strconv.Itoa(config.tproxyPort), "--tproxy-mark", "1") + common.RunCommand("ip6tables", "-t", "mangle", "-A", "PREROUTING", "-j", "XPROXY6") +} diff --git a/cmd/proxy/config.go b/cmd/proxy/config.go new file mode 100644 index 0000000..0384543 --- /dev/null +++ b/cmd/proxy/config.go @@ -0,0 +1,84 @@ +package proxy + +var dnsConfig = `{ + "dns": { + "servers": [ + "localhost" + ] + } +}` + +var routeConfig = `{ + "routing": { + "domainStrategy": "AsIs", + "rules": [ + { + "type": "field", + "network": "tcp,udp", + "outboundTag": "node" + } + ] + } +}` + +var outboundsConfig = `{ + "outbounds": [ + { + "tag": "node", + "protocol": "freedom", + "settings": {} + } + ] +}` + +func httpConfig(tag string, port int, sniff sniffObject) interface{} { + type empty struct{} + return inboundObject{ + Tag: tag, + Port: port, + Protocol: "http", + Settings: empty{}, + StreamSettings: empty{}, + Sniffing: sniff, + } +} + +func socksConfig(tag string, port int, sniff sniffObject) interface{} { + type empty struct{} + type socksObject struct { + UDP bool `json:"udp"` + } + return inboundObject{ + Tag: tag, + Port: port, + Protocol: "socks", + Settings: socksObject{UDP: true}, + StreamSettings: empty{}, + Sniffing: sniff, + } +} + +func tproxyConfig(tag string, port int, sniff sniffObject) interface{} { + type tproxyObject struct { + Network string `json:"network"` + FollowRedirect bool `json:"followRedirect"` + } + type tproxyStreamObject struct { + Sockopt struct { + Tproxy string `json:"tproxy"` + } `json:"sockopt"` + } + tproxyStream := tproxyStreamObject{} + tproxyStream.Sockopt.Tproxy = "tproxy" + return inboundObject{ + Tag: tag, + Port: port, + Protocol: "dokodemo-door", + Settings: tproxyObject{ + Network: "tcp,udp", + FollowRedirect: true, + }, + StreamSettings: tproxyStream, + Sniffing: sniff, + } +} diff --git a/cmd/proxy/load.go b/cmd/proxy/load.go new file mode 100644 index 0000000..33d0e7b --- /dev/null +++ b/cmd/proxy/load.go @@ -0,0 +1,65 @@ +package proxy + +import ( + "XProxy/cmd/common" + "encoding/json" + log "github.com/sirupsen/logrus" +) + +func saveConfig(configDir string, caption string, content string, overwrite bool) { + filePath := configDir + "/" + caption + ".json" + common.WriteFile(filePath, content+"\n", overwrite) +} + +func jsonEncode(raw interface{}) string { + jsonOutput, _ := json.MarshalIndent(raw, "", " ") // json encode + return string(jsonOutput) +} + +func loadLog(logLevel string, logDir string) string { + if logLevel != "debug" && logLevel != "info" && + logLevel != "warning" && logLevel != "error" && logLevel != "none" { + log.Warningf("Unknown log level -> %s", logLevel) + logLevel = "warning" // using `warning` as default + } + return jsonEncode(logObject{ + Loglevel: logLevel, + Access: logDir + "/access.log", + Error: logDir + "/error.log", + }) +} + +func loadInbounds(config Config) string { + inbounds := inboundsObject{} + sniff := sniffObject{ + Enabled: config.Sniff, + RouteOnly: !config.Redirect, + DestOverride: []string{"http", "tls"}, + } + inbounds.Inbounds = append(inbounds.Inbounds, tproxyConfig("tproxy", config.V4TProxyPort, sniff)) + inbounds.Inbounds = append(inbounds.Inbounds, tproxyConfig("tproxy6", config.V6TProxyPort, sniff)) + for tag, port := range config.HttpInbounds { + inbounds.Inbounds = append(inbounds.Inbounds, httpConfig(tag, port, sniff)) + } + for tag, port := range config.SocksInbounds { + inbounds.Inbounds = append(inbounds.Inbounds, socksConfig(tag, port, sniff)) + } + for _, addon := range config.AddOnInbounds { + inbounds.Inbounds = append(inbounds.Inbounds, addon) + } + return jsonEncode(inbounds) +} + +func Load(configDir string, exposeDir string, config Config) { + common.CreateFolder(exposeDir + "/log") + common.CreateFolder(exposeDir + "/config") + common.CreateFolder(configDir) + saveConfig(exposeDir+"/config", "dns", dnsConfig, false) + saveConfig(exposeDir+"/config", "route", routeConfig, false) + saveConfig(exposeDir+"/config", "outbounds", outboundsConfig, false) + saveConfig(configDir, "inbounds", loadInbounds(config), true) + saveConfig(configDir, "log", loadLog(config.LogLevel, exposeDir+"/log"), true) + for _, configFile := range common.ListFiles(exposeDir+"/config", ".json") { + common.CopyFile(exposeDir+"/config/"+configFile, configDir+"/"+configFile) + } +} diff --git a/cmd/proxy/object.go b/cmd/proxy/object.go new file mode 100644 index 0000000..5b444ac --- /dev/null +++ b/cmd/proxy/object.go @@ -0,0 +1,37 @@ +package proxy + +type Config struct { + Sniff bool + Redirect bool + V4TProxyPort int + V6TProxyPort int + LogLevel string + HttpInbounds map[string]int + SocksInbounds map[string]int + AddOnInbounds []interface{} +} + +type logObject struct { + Loglevel string `json:"loglevel"` + Access string `json:"access"` + Error string `json:"error"` +} + +type inboundsObject struct { + Inbounds []interface{} `json:"inbounds"` +} + +type sniffObject struct { + Enabled bool `json:"enabled"` + RouteOnly bool `json:"routeOnly"` + DestOverride []string `json:"destOverride"` +} + +type inboundObject struct { + Tag string `json:"tag"` + Port int `json:"port"` + Protocol string `json:"protocol"` + Settings interface{} `json:"settings"` + StreamSettings interface{} `json:"streamSettings"` + Sniffing sniffObject `json:"sniffing"` +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..96c2d3f --- /dev/null +++ b/main.go @@ -0,0 +1,19 @@ +package main + +import ( + "XProxy/cmd/network" + "fmt" + log "github.com/sirupsen/logrus" +) + +func main() { + log.SetLevel(log.DebugLevel) + + fmt.Println("xproxy start") + //common.CreateFolder("/tmp/test") + //fmt.Println(common.IsFileExist("/tmp/1.jpg")) + //fmt.Println(common.ListFiles("/xproxy/config", ".json")) + net = network.Config{ + V4RouteTable: 12, + } +} diff --git a/src/config.go b/src/config.go index 0f9c17f..bcaab03 100644 --- a/src/config.go +++ b/src/config.go @@ -3,9 +3,7 @@ package main import ( log "github.com/sirupsen/logrus" "gopkg.in/yaml.v3" - "net" "os" - "strings" ) var v4Bypass []string @@ -66,22 +64,6 @@ type Config struct { } `yaml:"network"` } -func isIP(ipAddr string, isCidr bool) bool { - if !isCidr { - return net.ParseIP(ipAddr) != nil - } - _, _, err := net.ParseCIDR(ipAddr) - return err == nil -} - -func isIPv4(ipAddr string, isCidr bool) bool { - return isIP(ipAddr, isCidr) && strings.Contains(ipAddr, ".") -} - -func isIPv6(ipAddr string, isCidr bool) bool { - return isIP(ipAddr, isCidr) && strings.Contains(ipAddr, ":") -} - func loadConfig(configFile string) { if !isFileExist(configFile) { // load default configure log.Infof("Load default configure -> %s", configFile) diff --git a/src/load.go b/src/load.go deleted file mode 100644 index 5b2d60a..0000000 --- a/src/load.go +++ /dev/null @@ -1,286 +0,0 @@ -package main - -import ( - "encoding/json" - log "github.com/sirupsen/logrus" - "io" - "io/ioutil" - "net/http" - "os" - "os/exec" - "strings" - "syscall" -) - -var logConfig = `{ - "log": { - "loglevel": "${LEVEL}", - "access": "${DIR}/access.log", - "error": "${DIR}/error.log" - } -}` - -var dnsConfig = `{ - "dns": { - "servers": [ - "localhost" - ] - } -}` - -var routeConfig = `{ - "routing": { - "domainStrategy": "AsIs", - "rules": [ - { - "type": "field", - "network": "tcp,udp", - "outboundTag": "node" - } - ] - } -}` - -var outboundsConfig = `{ - "outbounds": [ - { - "tag": "node", - "protocol": "freedom", - "settings": {} - } - ] -}` - -type inboundsSettings struct { - Inbounds []interface{} `json:"inbounds"` -} - -type sniffSettings struct { - Enabled bool `json:"enabled"` - RouteOnly bool `json:"routeOnly"` - DestOverride []string `json:"destOverride"` -} - -type inboundSettings struct { - Tag string `json:"tag"` - Port int `json:"port"` - Protocol string `json:"protocol"` - Settings interface{} `json:"settings"` - StreamSettings interface{} `json:"streamSettings"` - Sniffing sniffSettings `json:"sniffing"` -} - -func runCommand(command ...string) (int, string) { - log.Debugf("Running system command -> %v", command) - process := exec.Command(command[0], command[1:]...) - output, _ := process.CombinedOutput() - log.Debugf("Command %v -> \n%s", command, string(output)) - code := process.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() - if code != 0 { - log.Warningf("Command %v return code %d", command, code) - } - return code, string(output) -} - -func isFileExist(filePath string) bool { - s, err := os.Stat(filePath) - if err != nil { // file or folder not exist - return false - } - return !s.IsDir() -} - -func createFolder(folderPath string) { - log.Debugf("Create folder -> %s", folderPath) - err := os.MkdirAll(folderPath, 0755) - if err != nil { - log.Panicf("Failed to create folder -> %s", folderPath) - } -} - -func listFolder(folderPath string, suffix string) []string { - var fileList []string - files, err := ioutil.ReadDir(folderPath) - if err != nil { - log.Panicf("Failed to list folder -> %s", folderPath) - } - for _, file := range files { - if strings.HasSuffix(file.Name(), suffix) { - fileList = append(fileList, file.Name()) - } - } - return fileList -} - -func copyFile(source string, target string) { - log.Infof("Copy file `%s` => `%s`", source, target) - srcFile, err := os.Open(source) - if err != nil { - log.Panicf("Failed to open file -> %s", source) - } - dstFile, err := os.OpenFile(target, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644) - if err != nil { - log.Panicf("Failed to open file -> %s", target) - } - _, err = io.Copy(dstFile, srcFile) - if err != nil { - log.Panicf("Failed to copy from `%s` to `%s`", source, target) - } -} - -func downloadFile(url string, file string) bool { - log.Debugf("File download %s => %s", url, file) - resp, err := http.Get(url) - if err != nil { - log.Errorf("Download %s error -> %v", url, err) - return false - } - defer func(Body io.ReadCloser) { - _ = Body.Close() - }(resp.Body) - out, err := os.OpenFile(file, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644) - if err != nil { - _ = resp.Body.Close() - log.Panicf("Open %s error -> %v", file, err) - } - _, err = io.Copy(out, resp.Body) - _ = resp.Body.Close() - if err != nil { - log.Panicf("File %s save error -> %v", file, err) - } - log.Infof("Download success `%s` => `%s`", url, file) - return true -} - -func saveConfig(configDir string, caption string, content string, overwrite bool) { - filePath := configDir + "/" + caption + ".json" - if !overwrite && isFileExist(filePath) { // file exist and don't overwrite - log.Debugf("Skip loading config -> %s", filePath) - return - } - log.Debugf("Loading %s -> \n%s", filePath, content) - err := os.WriteFile(filePath, []byte(content), 0644) - if err != nil { - log.Panicf("File %s -> %v", caption, err) - } -} - -func loadHttpConfig(tag string, port int, sniffObject sniffSettings) interface{} { - type empty struct{} - return inboundSettings{ - Tag: tag, - Port: port, - Protocol: "http", - Settings: empty{}, - StreamSettings: empty{}, - Sniffing: sniffObject, - } -} - -func loadSocksConfig(tag string, port int, sniffObject sniffSettings) interface{} { - type empty struct{} - type socksSettings struct { - UDP bool `json:"udp"` - } - return inboundSettings{ - Tag: tag, - Port: port, - Protocol: "socks", - Settings: socksSettings{UDP: true}, - StreamSettings: empty{}, - Sniffing: sniffObject, - } -} - -func loadTProxyConfig(tag string, port int, sniffObject sniffSettings) interface{} { - type tproxySettings struct { - Network string `json:"network"` - FollowRedirect bool `json:"followRedirect"` - } - type tproxyStreamSettings struct { - Sockopt struct { - Tproxy string `json:"tproxy"` - } `json:"sockopt"` - } - tproxyStream := tproxyStreamSettings{} - tproxyStream.Sockopt.Tproxy = "tproxy" - return inboundSettings{ - Tag: tag, - Port: port, - Protocol: "dokodemo-door", - Settings: tproxySettings{ - Network: "tcp,udp", - FollowRedirect: true, - }, - StreamSettings: tproxyStream, - Sniffing: sniffObject, - } -} - -func loadProxy(configDir string, exposeDir string) { - createFolder(exposeDir + "/log") - createFolder(exposeDir + "/config") - createFolder(configDir) - saveConfig(exposeDir+"/config", "dns", dnsConfig+"\n", false) - saveConfig(exposeDir+"/config", "route", routeConfig+"\n", false) - saveConfig(exposeDir+"/config", "outbounds", outboundsConfig+"\n", false) - - logConfig = strings.ReplaceAll(logConfig, "${LEVEL}", logLevel) - logConfig = strings.ReplaceAll(logConfig, "${DIR}", exposeDir+"/log") - saveConfig(configDir, "log", logConfig+"\n", true) - - inbounds := inboundsSettings{} - sniff := sniffSettings{ - Enabled: enableSniff, - RouteOnly: !enableRedirect, - DestOverride: []string{"http", "tls"}, - } - inbounds.Inbounds = append(inbounds.Inbounds, loadTProxyConfig("tproxy", v4TProxyPort, sniff)) - inbounds.Inbounds = append(inbounds.Inbounds, loadTProxyConfig("tproxy6", v6TProxyPort, sniff)) - for tag, port := range httpInbounds { - inbounds.Inbounds = append(inbounds.Inbounds, loadHttpConfig(tag, port, sniff)) - } - for tag, port := range socksInbounds { - inbounds.Inbounds = append(inbounds.Inbounds, loadSocksConfig(tag, port, sniff)) - } - for _, addon := range addOnInbounds { - inbounds.Inbounds = append(inbounds.Inbounds, addon) - } - inboundsConfig, _ := json.MarshalIndent(inbounds, "", " ") // json encode - saveConfig(configDir, "inbounds", string(inboundsConfig)+"\n", true) - - for _, configFile := range listFolder(exposeDir+"/config", ".json") { - if configFile == "log.json" || configFile == "inbounds.json" { - log.Warningf("Config file `%s` will be overrided", configFile) - } - copyFile(exposeDir+"/config/"+configFile, configDir+"/"+configFile) - } -} - -func extractGeoFile(archivePath string, geoFile string, targetDir string) { - if isFileExist(targetDir + "/" + geoFile) { - log.Debugf("Asset %s exist -> skip extract", geoFile) - return - } - log.Infof("Extract asset file -> %s", targetDir+"/"+geoFile) - runCommand("tar", "xvf", archivePath, "./"+geoFile, "-C", targetDir) -} - -func loadGeoIp(assetDir string) { - createFolder(assetDir) - extractGeoFile(assetFile, "geoip.dat", assetDir) -} - -func loadGeoSite(assetDir string) { - createFolder(assetDir) - extractGeoFile(assetFile, "geosite.dat", assetDir) -} - -func updateAssets(assetDir string) { - if len(updateUrls) != 0 { - log.Info("Start update assets") - for file, url := range updateUrls { - downloadFile(url, assetDir+"/"+file) - } - } -} diff --git a/src/network.go b/src/network.go deleted file mode 100644 index c719d99..0000000 --- a/src/network.go +++ /dev/null @@ -1,98 +0,0 @@ -package main - -import ( - log "github.com/sirupsen/logrus" - "os" - "regexp" - "strconv" -) - -func loadDns() { - if len(dnsServer) == 0 { - log.Info("Using system DNS server") - return - } - log.Infof("Setting up DNS server -> %v", dnsServer) - dnsContent := "" - for _, address := range dnsServer { - dnsContent += "nameserver " + address + "\n" - } - err := os.WriteFile("/etc/resolv.conf", []byte(dnsContent), 0644) - if err != nil { - log.Panic("Setting up DNS failed") - } -} - -func loadNetwork() { - log.Info("Enabled IP forward") - runCommand("sysctl", "-w", "net.ipv4.ip_forward=1") - runCommand("sysctl", "-w", "net.ipv6.conf.all.forwarding=1") - - log.Info("Flush system IP configure") - runCommand("ip", "link", "set", "eth0", "down") - runCommand("ip", "-4", "addr", "flush", "dev", "eth0") - runCommand("ip", "-6", "addr", "flush", "dev", "eth0") - runCommand("ip", "link", "set", "eth0", "down") - - log.Info("Setting up system IP configure") - if v4Address != "" { - runCommand("ip", "-4", "addr", "add", v4Address, "dev", "eth0") - } - if v4Gateway != "" { - runCommand("ip", "-4", "route", "add", "default", "via", v4Gateway) - } - if v6Address != "" { - runCommand("ip", "-6", "addr", "add", v6Address, "dev", "eth0") - } - if v6Gateway != "" { - runCommand("ip", "-6", "route", "add", "default", "via", v6Gateway) - } -} - -func v4SysBypass() { - _, output := runCommand("ip", "-4", "addr") - for _, temp := range regexp.MustCompile(`inet (\S+)`).FindAllStringSubmatch(output, -1) { - v4Bypass = append(v4Bypass, temp[1]) - } -} - -func v6SysBypass() { - _, output := runCommand("ip", "-6", "addr") - for _, temp := range regexp.MustCompile(`inet6 (\S+)`).FindAllStringSubmatch(output, -1) { - v6Bypass = append(v6Bypass, temp[1]) - } -} - -func loadTProxy() { - log.Info("Setting up TProxy of IPv4") - v4TableNum := strconv.Itoa(v4RouteTable) - runCommand("ip", "-4", "rule", "add", "fwmark", "1", "table", v4TableNum) - runCommand("ip", "-4", "route", "add", "local", "0.0.0.0/0", "dev", "lo", "table", v4TableNum) - runCommand("iptables", "-t", "mangle", "-N", "XPROXY") - v4SysBypass() - log.Infof("Setting up IPv4 bypass CIDR -> %v", v4Bypass) - for _, cidr := range v4Bypass { - runCommand("iptables", "-t", "mangle", "-A", "XPROXY", "-d", cidr, "-j", "RETURN") - } - runCommand("iptables", "-t", "mangle", "-A", "XPROXY", "-p", "tcp", "-j", "TPROXY", - "--on-port", strconv.Itoa(v4TProxyPort), "--tproxy-mark", "1") - runCommand("iptables", "-t", "mangle", "-A", "XPROXY", "-p", "udp", "-j", "TPROXY", - "--on-port", strconv.Itoa(v4TProxyPort), "--tproxy-mark", "1") - runCommand("iptables", "-t", "mangle", "-A", "PREROUTING", "-j", "XPROXY") - - log.Info("Setting up TProxy of IPv6") - v6TableNum := strconv.Itoa(v6RouteTable) - runCommand("ip", "-6", "rule", "add", "fwmark", "1", "table", v6TableNum) - runCommand("ip", "-6", "route", "add", "local", "::/0", "dev", "lo", "table", v6TableNum) - runCommand("ip6tables", "-t", "mangle", "-N", "XPROXY6") - v6SysBypass() - log.Infof("Setting up IPv6 bypass CIDR -> %v", v6Bypass) - for _, cidr := range v6Bypass { - runCommand("ip6tables", "-t", "mangle", "-A", "XPROXY6", "-d", cidr, "-j", "RETURN") - } - runCommand("ip6tables", "-t", "mangle", "-A", "XPROXY6", "-p", "tcp", "-j", "TPROXY", - "--on-port", strconv.Itoa(v6TProxyPort), "--tproxy-mark", "1") - runCommand("ip6tables", "-t", "mangle", "-A", "XPROXY6", "-p", "udp", "-j", "TPROXY", - "--on-port", strconv.Itoa(v6TProxyPort), "--tproxy-mark", "1") - runCommand("ip6tables", "-t", "mangle", "-A", "PREROUTING", "-j", "XPROXY6") -}