diff --git a/cmd/common/file.go b/cmd/common/file.go index 7d7907e..92744a6 100644 --- a/cmd/common/file.go +++ b/cmd/common/file.go @@ -1,94 +1,89 @@ package common import ( - log "github.com/sirupsen/logrus" - "io" - "io/ioutil" - "net/http" - "os" - "strings" + 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) - } + log.Debugf("Create folder -> %s", folderPath) + if err := os.MkdirAll(folderPath, 0755); 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() + 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) - } + 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) + if err := os.WriteFile(filePath, []byte(content), 0644); 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 + 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) - } + log.Infof("Copy file `%s` => `%s`", source, target) + if IsFileExist(target) { + log.Debugf("File `%s` will be overrided", target) + } + srcFile, err := os.Open(source) + defer srcFile.Close() + 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) + defer dstFile.Close() + if err != nil { + log.Panicf("Failed to open file -> %s", target) + } + if _, err = io.Copy(dstFile, srcFile); 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) + log.Debugf("File download `%s` => `%s`", url, file) + resp, err := http.Get(url) + defer resp.Body.Close() + if err != nil { + log.Errorf("Download `%s` error -> %v", url, err) + return + } + output, err := os.OpenFile(file, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644) + defer output.Close() + if err != nil { + log.Panicf("Open `%s` error -> %v", file, err) + } + if _, err = io.Copy(output, resp.Body); err != nil { + log.Panicf("File `%s` save error -> %v", file, err) + } + log.Infof("Download success `%s` => `%s`", url, file) } diff --git a/cmd/common/func.go b/cmd/common/func.go new file mode 100644 index 0000000..778e458 --- /dev/null +++ b/cmd/common/func.go @@ -0,0 +1,43 @@ +package common + +import ( + "encoding/json" + log "github.com/sirupsen/logrus" + "net" + "os/exec" + "strings" + "syscall" +) + +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 JsonEncode(raw interface{}) string { + jsonOutput, _ := json.MarshalIndent(raw, "", " ") // json encode + return string(jsonOutput) +} + +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/common/net.go b/cmd/common/net.go deleted file mode 100644 index 7ac05da..0000000 --- a/cmd/common/net.go +++ /dev/null @@ -1,22 +0,0 @@ -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 deleted file mode 100644 index b25c3d7..0000000 --- a/cmd/common/sys.go +++ /dev/null @@ -1,19 +0,0 @@ -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/proxy/config.go b/cmd/proxy/config.go index 0384543..d12fd83 100644 --- a/cmd/proxy/config.go +++ b/cmd/proxy/config.go @@ -1,5 +1,10 @@ package proxy +import ( + "XProxy/cmd/common" + log "github.com/sirupsen/logrus" +) + var dnsConfig = `{ "dns": { "servers": [ @@ -31,54 +36,92 @@ var outboundsConfig = `{ ] }` -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, - } +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"` +} + +func loadLogConfig(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 common.JsonEncode(logObject{ + Loglevel: logLevel, + Access: logDir + "/access.log", + Error: logDir + "/error.log", + }) } -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 loadHttpConfig(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 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, - } +func loadSocksConfig(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 loadTProxyConfig(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/main.go similarity index 50% rename from cmd/proxy/load.go rename to cmd/proxy/main.go index 33d0e7b..fcb25a4 100644 --- a/cmd/proxy/load.go +++ b/cmd/proxy/main.go @@ -2,52 +2,45 @@ package proxy import ( "XProxy/cmd/common" - "encoding/json" - log "github.com/sirupsen/logrus" ) +type Config struct { + Sniff bool + Redirect bool + V4TProxyPort int + V6TProxyPort int + LogLevel string + HttpInbounds map[string]int + SocksInbounds map[string]int + AddOnInbounds []interface{} +} + 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)) + var inbounds []interface{} + inbounds = append(inbounds, loadTProxyConfig("tproxy", config.V4TProxyPort, sniff)) + inbounds = append(inbounds, loadTProxyConfig("tproxy6", config.V6TProxyPort, sniff)) for tag, port := range config.HttpInbounds { - inbounds.Inbounds = append(inbounds.Inbounds, httpConfig(tag, port, sniff)) + inbounds = append(inbounds, loadHttpConfig(tag, port, sniff)) } for tag, port := range config.SocksInbounds { - inbounds.Inbounds = append(inbounds.Inbounds, socksConfig(tag, port, sniff)) + inbounds = append(inbounds, loadSocksConfig(tag, port, sniff)) } for _, addon := range config.AddOnInbounds { - inbounds.Inbounds = append(inbounds.Inbounds, addon) + inbounds = append(inbounds, addon) } - return jsonEncode(inbounds) + return common.JsonEncode(inboundsObject{ + Inbounds: inbounds, + }) } func Load(configDir string, exposeDir string, config Config) { @@ -58,7 +51,7 @@ func Load(configDir string, exposeDir string, config Config) { 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) + saveConfig(configDir, "log", loadLogConfig(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 deleted file mode 100644 index 5b444ac..0000000 --- a/cmd/proxy/object.go +++ /dev/null @@ -1,37 +0,0 @@ -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 index 1b6deac..5af74f6 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,8 @@ package main import ( + "XProxy/cmd/network" + "XProxy/cmd/proxy" "fmt" log "github.com/sirupsen/logrus" ) @@ -10,4 +12,28 @@ func main() { fmt.Println("xproxy start") + network.Load(nil, network.Config{ + RouteTable: 100, + TProxyPort: 7288, + Address: "192.168.2.2", + Gateway: "192.168.2.1", + Bypass: make([]string, 0), + }, network.Config{ + RouteTable: 106, + TProxyPort: 7289, + Address: "fc00::2", + Gateway: "fc00::1", + Bypass: make([]string, 0), + }) + + proxy.Load("/etc/xproxy", "/xproxy", proxy.Config{ + Sniff: true, + Redirect: true, + V4TProxyPort: 7288, + V6TProxyPort: 7289, + LogLevel: "debug", + HttpInbounds: nil, + SocksInbounds: nil, + AddOnInbounds: nil, + }) }