mirror of
https://github.com/e1732a364fed/v2ray_simple.git
synced 2025-12-24 13:27:56 +08:00
306 lines
7.2 KiB
Go
306 lines
7.2 KiB
Go
package main
|
||
|
||
import (
|
||
"flag"
|
||
"fmt"
|
||
"io"
|
||
"log"
|
||
"net/http"
|
||
"os"
|
||
|
||
vs "github.com/e1732a364fed/v2ray_simple"
|
||
"go.uber.org/zap"
|
||
|
||
"github.com/e1732a364fed/v2ray_simple/advLayer"
|
||
"github.com/e1732a364fed/v2ray_simple/netLayer"
|
||
"github.com/e1732a364fed/v2ray_simple/proxy"
|
||
"github.com/e1732a364fed/v2ray_simple/utils"
|
||
)
|
||
|
||
//本文件下所有命令的输出统一使用 fmt 而不是 log
|
||
|
||
var (
|
||
cmdPrintSupportedProtocols bool
|
||
|
||
interactive_mode bool
|
||
nodownload bool
|
||
cmdPrintVer bool
|
||
)
|
||
|
||
func init() {
|
||
flag.BoolVar(&cmdPrintSupportedProtocols, "sp", false, "print supported protocols")
|
||
flag.BoolVar(&interactive_mode, "i", false, "enable interactive commandline mode")
|
||
flag.BoolVar(&nodownload, "nd", false, "don't automatically download any extra data files")
|
||
flag.BoolVar(&cmdPrintVer, "v", false, "print the version string then exit")
|
||
|
||
//本文件 中定义的 CliCmd都是直接返回运行结果的、无需进一步交互的命令
|
||
|
||
cliCmdList = append(cliCmdList, CliCmd{
|
||
"生成一个随机的uuid供你参考", func() {
|
||
generateAndPrintUUID()
|
||
},
|
||
})
|
||
|
||
cliCmdList = append(cliCmdList, CliCmd{
|
||
"下载geosite原文件", func() {
|
||
tryDownloadGeositeSource()
|
||
},
|
||
})
|
||
|
||
cliCmdList = append(cliCmdList, CliCmd{
|
||
"打印当前版本所支持的所有协议", func() {
|
||
printSupportedProtocols()
|
||
},
|
||
})
|
||
|
||
cliCmdList = append(cliCmdList, CliCmd{
|
||
"查询当前状态", func() {
|
||
printAllState(os.Stdout, false)
|
||
},
|
||
})
|
||
|
||
}
|
||
|
||
//运行一些 执行后立即退出程序的 命令
|
||
func runExitCommands() (atLeastOneCalled bool) {
|
||
if cmdPrintVer {
|
||
atLeastOneCalled = true
|
||
printVersion_simple()
|
||
}
|
||
|
||
if cmdPrintSupportedProtocols {
|
||
atLeastOneCalled = true
|
||
printSupportedProtocols()
|
||
}
|
||
|
||
return
|
||
}
|
||
|
||
//在开始正式代理前, 先运行一些需要运行的命令与函数
|
||
func runPreCommands() {
|
||
|
||
if !nodownload {
|
||
tryDownloadMMDB()
|
||
}
|
||
}
|
||
|
||
func generateAndPrintUUID() {
|
||
fmt.Printf("New random uuid : %s\n", utils.GenerateUUIDStr())
|
||
}
|
||
|
||
func printSupportedProtocols() {
|
||
fmt.Printf("Support tcp/udp/tproxy/unix domain socket/tls/uTls by default.\n")
|
||
proxy.PrintAllServerNames()
|
||
proxy.PrintAllClientNames()
|
||
advLayer.PrintAllProtocolNames()
|
||
}
|
||
|
||
//see https://dev.maxmind.com/geoip/geolite2-free-geolocation-data?lang=en
|
||
func tryDownloadMMDB() {
|
||
|
||
if utils.FileExist(utils.GetFilePath(netLayer.GeoipFileName)) {
|
||
return
|
||
}
|
||
|
||
const mmdbDownloadLink = "https://cdn.jsdelivr.net/gh/Loyalsoldier/geoip@release/Country.mmdb"
|
||
|
||
fmt.Printf("No %s found,start downloading from %s\n", netLayer.GeoipFileName, mmdbDownloadLink)
|
||
|
||
resp, err := http.Get(mmdbDownloadLink)
|
||
|
||
if err != nil {
|
||
fmt.Printf("Download mmdb failed %s\n", err.Error())
|
||
return
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
fmt.Printf("Download mmdb got bad status: %s\n", resp.Status)
|
||
return
|
||
}
|
||
|
||
out, err := os.Create(netLayer.GeoipFileName)
|
||
if err != nil {
|
||
fmt.Printf("Can Download mmdb but Can't Create File,%s \n", err.Error())
|
||
return
|
||
}
|
||
defer out.Close()
|
||
|
||
_, err = io.Copy(out, resp.Body)
|
||
if err != nil {
|
||
fmt.Printf("Write downloaded mmdb to file failed: %s\n", err.Error())
|
||
return
|
||
}
|
||
fmt.Printf("Download mmdb success!\n")
|
||
|
||
}
|
||
|
||
func printAllState(w io.Writer, withoutTProxy bool) {
|
||
fmt.Fprintln(w, "activeConnectionCount", vs.ActiveConnectionCount)
|
||
fmt.Fprintln(w, "allDownloadBytesSinceStart", vs.AllDownloadBytesSinceStart)
|
||
fmt.Fprintln(w, "allUploadBytesSinceStart", vs.AllUploadBytesSinceStart)
|
||
|
||
for i, s := range allServers {
|
||
fmt.Fprintln(w, "inServer", i, proxy.GetFullName(s), s.AddrStr())
|
||
|
||
}
|
||
|
||
if !withoutTProxy && len(tproxyList) > 0 {
|
||
for i, tc := range tproxyList {
|
||
fmt.Fprintln(w, "inServer", i+len(allServers), "tproxy", tc.String())
|
||
}
|
||
}
|
||
|
||
for i, c := range allClients {
|
||
fmt.Fprintln(w, "outClient", i, proxy.GetFullName(c), c.AddrStr())
|
||
}
|
||
|
||
}
|
||
|
||
//试图从自己已经配置好的节点去下载geosite源码文件, 如果没有节点则直连下载。
|
||
// 我们只需要一个dial配置即可. listen我们不使用配置文件的配置,而是自行监听一个随机端口用于http代理
|
||
func tryDownloadGeositeSource() {
|
||
|
||
var outClient proxy.Client
|
||
|
||
if defaultOutClient != nil && defaultOutClient.Name() != proxy.DirectName && defaultOutClient.Name() != proxy.RejectName {
|
||
outClient = defaultOutClient
|
||
fmt.Println("trying to download geosite through your proxy dial")
|
||
} else {
|
||
fmt.Println("trying to download geosite directly")
|
||
}
|
||
|
||
var proxyurl string
|
||
var listener io.Closer
|
||
|
||
if outClient != nil {
|
||
|
||
const tempClientConfStr = `
|
||
[[listen]]
|
||
protocol = "http"
|
||
`
|
||
|
||
clientConf, err := proxy.LoadTomlConfStr(tempClientConfStr)
|
||
if err != nil {
|
||
fmt.Println("can not create LoadTomlConfStr: ", err)
|
||
|
||
return
|
||
}
|
||
|
||
clientEndInServer, err := proxy.NewServer(clientConf.Listen[0])
|
||
if err != nil {
|
||
fmt.Println("can not create clientEndInServer: ", err)
|
||
return
|
||
}
|
||
listenAddrStr := netLayer.GetRandLocalPrivateAddr(true, false)
|
||
clientEndInServer.SetAddrStr(listenAddrStr)
|
||
|
||
listener = vs.ListenSer(clientEndInServer, outClient, nil)
|
||
|
||
proxyurl = "http://" + listenAddrStr
|
||
|
||
}
|
||
|
||
netLayer.DownloadCommunity_DomainListFiles(proxyurl)
|
||
|
||
if listener != nil {
|
||
listener.Close()
|
||
}
|
||
}
|
||
|
||
func hotLoadDialConfForRuntime(Default_uuid string, conf []*proxy.DialConf) {
|
||
for _, d := range conf {
|
||
|
||
if d.Uuid == "" && Default_uuid != "" {
|
||
d.Uuid = Default_uuid
|
||
}
|
||
|
||
outClient, err := proxy.NewClient(d)
|
||
if err != nil {
|
||
if ce := utils.CanLogErr("can not create outClient: "); ce != nil {
|
||
ce.Write(zap.Error(err))
|
||
}
|
||
continue
|
||
}
|
||
|
||
allClients = append(allClients, outClient)
|
||
if tag := outClient.GetTag(); tag != "" {
|
||
|
||
routingEnv.SetClient(tag, outClient)
|
||
|
||
}
|
||
}
|
||
|
||
if defaultOutClient == nil {
|
||
if len(allClients) > 0 {
|
||
defaultOutClient = allClients[0]
|
||
|
||
} else {
|
||
defaultOutClient = vs.DirectClient
|
||
}
|
||
}
|
||
|
||
}
|
||
func hotLoadListenConfForRuntime(conf []*proxy.ListenConf) {
|
||
|
||
for i, l := range conf {
|
||
inServer, err := proxy.NewServer(l)
|
||
if err != nil {
|
||
log.Println("can not create inServer: ", i, err)
|
||
return
|
||
}
|
||
lis := vs.ListenSer(inServer, defaultOutClient, &routingEnv)
|
||
if lis != nil {
|
||
listenCloserArray = append(listenCloserArray, lis)
|
||
allServers = append(allServers, inServer)
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
func loadSimpleServer() (result int, server proxy.Server) {
|
||
var hase bool
|
||
var eie utils.ErrInErr
|
||
server, hase, eie = proxy.ServerFromURL(simpleConf.ListenUrl)
|
||
if hase {
|
||
if ce := utils.CanLogErr("can not create local server"); ce != nil {
|
||
ce.Write(zap.String("error", eie.Error()))
|
||
}
|
||
result = -1
|
||
return
|
||
}
|
||
|
||
allServers = append(allServers, server)
|
||
|
||
if !server.CantRoute() && simpleConf.Route != nil {
|
||
|
||
netLayer.LoadMaxmindGeoipFile("")
|
||
|
||
//极简模式只支持通过 mycountry进行 geoip分流 这一种情况
|
||
routingEnv.RoutePolicy = netLayer.NewRoutePolicy()
|
||
if simpleConf.MyCountryISO_3166 != "" {
|
||
routingEnv.RoutePolicy.AddRouteSet(netLayer.NewRouteSetForMyCountry(simpleConf.MyCountryISO_3166))
|
||
|
||
}
|
||
}
|
||
return
|
||
}
|
||
|
||
func loadSimpleClient() (result int, client proxy.Client) {
|
||
var hase bool
|
||
var eie utils.ErrInErr
|
||
client, hase, eie = proxy.ClientFromURL(simpleConf.DialUrl)
|
||
if hase {
|
||
if ce := utils.CanLogErr("can not create remote client"); ce != nil {
|
||
ce.Write(zap.String("error", eie.Error()))
|
||
}
|
||
result = -1
|
||
return
|
||
}
|
||
|
||
allClients = append(allClients, client)
|
||
return
|
||
}
|