mirror of https://github.com/dnomd343/XProxy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
231 lines
6.7 KiB
231 lines
6.7 KiB
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
log "github.com/sirupsen/logrus"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
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 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"`
|
|
}
|
|
|
|
type inboundsSettings struct {
|
|
Inbounds []interface{} `json:"inbounds"`
|
|
}
|
|
|
|
func runCommand(command []string) bool {
|
|
log.Debugf("Running system command -> %v", command)
|
|
// TODO: run system command
|
|
return true
|
|
}
|
|
|
|
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("Loading folder -> %s", folderPath)
|
|
err := os.MkdirAll(folderPath, 0755)
|
|
if err != nil {
|
|
log.Errorf("Failed to create folder -> %s", folderPath)
|
|
panic("Create folder failed")
|
|
}
|
|
}
|
|
|
|
func listFolder(folderPath string, suffix string) []string {
|
|
var fileList []string
|
|
files, err := ioutil.ReadDir(folderPath)
|
|
if err != nil {
|
|
log.Errorf("Failed to list folder -> %s", folderPath)
|
|
panic("List folder failed")
|
|
}
|
|
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.Errorf("Failed to open file -> %s", source)
|
|
panic("Open file failed")
|
|
}
|
|
dstFile, err := os.OpenFile(target, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
|
|
if err != nil {
|
|
log.Errorf("Failed to open file -> %s", target)
|
|
panic("Open file failed")
|
|
}
|
|
_, err = io.Copy(dstFile, srcFile)
|
|
if err != nil {
|
|
log.Errorf("Failed to copy from `%s` to `%s`", source, target)
|
|
panic("Copy file failed")
|
|
}
|
|
}
|
|
|
|
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.Errorf("File %s -> %v", caption, err)
|
|
panic("File save error")
|
|
}
|
|
}
|
|
|
|
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)
|
|
|
|
inboundsObject := inboundsSettings{}
|
|
sniffObject := sniffSettings{
|
|
Enabled: enableSniff,
|
|
RouteOnly: !enableRedirect,
|
|
DestOverride: []string{"http", "tls"},
|
|
}
|
|
inboundsObject.Inbounds = append(inboundsObject.Inbounds, loadTProxyConfig("tproxy", v4TProxyPort, sniffObject))
|
|
inboundsObject.Inbounds = append(inboundsObject.Inbounds, loadTProxyConfig("tproxy6", v6TProxyPort, sniffObject))
|
|
for tag, port := range httpInbounds {
|
|
inboundsObject.Inbounds = append(inboundsObject.Inbounds, loadHttpConfig(tag, port, sniffObject))
|
|
}
|
|
for tag, port := range socksInbounds {
|
|
inboundsObject.Inbounds = append(inboundsObject.Inbounds, loadSocksConfig(tag, port, sniffObject))
|
|
}
|
|
for _, addon := range addOnInbounds {
|
|
inboundsObject.Inbounds = append(inboundsObject.Inbounds, addon)
|
|
}
|
|
inboundsConfig, _ := json.MarshalIndent(inboundsObject, "", " ") // 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)
|
|
}
|
|
}
|
|
|