feature:交互模式添加 热加载url配置功能;修订代码,文档;

This commit is contained in:
e1732a364fed
2000-01-01 00:00:00 +00:00
parent a6ecc4106e
commit 90ec238f6b
10 changed files with 509 additions and 348 deletions

View File

@@ -206,6 +206,8 @@ verysimple -c server.toml
## 关于证书
<details>
自己生成证书!而且最好是用 自己真实拥有的域名使用acme.sh等脚本申请免费证书特别是建站等情况。
而且用了真证书后,别忘了把配置文件中的 `insecure=true` 给删掉.
@@ -249,6 +251,14 @@ openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.crt -CAkey ca.key -se
在你的服务端下载好程序后,运行 `verysimple -i` 开启交互模式,然后按向下箭头 找到对应选项,按回车 来自动生成tls证书。
</details>
# 技术相关
<details>
<summary>技术相关</summary>
## 创新点
@@ -531,6 +541,9 @@ https://github.com/e1732a364fed/v2ray_simple/discussions/3
./verysimple -c ../../examples/quic.server.toml -ll 0
```
</details>
## 测速
测试环境ubuntu虚拟机, 使用开源测试工具

View File

@@ -10,110 +10,43 @@ import (
vs "github.com/e1732a364fed/v2ray_simple"
"github.com/e1732a364fed/v2ray_simple/netLayer"
"github.com/e1732a364fed/v2ray_simple/proxy"
"github.com/e1732a364fed/v2ray_simple/tlsLayer"
"github.com/e1732a364fed/v2ray_simple/utils"
"github.com/manifoldco/promptui"
)
type CliCmd struct {
Name string
f func()
}
func (cc CliCmd) String() string {
return cc.Name
}
func nlist(list []CliCmd) (result []string) {
for _, v := range list {
result = append(result, v.Name)
}
return
}
func flist(list []CliCmd) (result []func()) {
for _, v := range list {
result = append(result, v.f)
}
return
}
var cliCmdList = []CliCmd{
{
"生成随机ssl证书", func() {
const certFn = "cert.pem"
const keyFn = "cert.key"
if utils.FileExist(certFn) {
utils.PrintStr(certFn)
utils.PrintStr(" 已存在!\n")
return
}
if utils.FileExist(keyFn) {
utils.PrintStr(keyFn)
utils.PrintStr(" 已存在!\n")
return
}
err := tlsLayer.GenerateRandomCertKeyFiles(certFn, keyFn)
if err == nil {
utils.PrintStr("生成成功!请查看目录中的 ")
utils.PrintStr(certFn)
utils.PrintStr(" 和 ")
utils.PrintStr(keyFn)
utils.PrintStr("\n")
} else {
utils.PrintStr("生成失败,")
utils.PrintStr(err.Error())
utils.PrintStr("\n")
}
},
},
}
func getStandardConfFromCurrentState() (sc proxy.StandardConf) {
for _, c := range allClients {
dc := c.GetBase().DialConf
sc.Dial = append(sc.Dial, dc)
}
for _, s := range allServers {
lc := s.GetBase().ListenConf
sc.Listen = append(sc.Listen, lc)
}
return
}
func init() {
//cli.go 中添加的 CliCmd都是需进一步交互的命令
var getStandardConfFromCurrentState = func() (sc proxy.StandardConf) {
for _, c := range allClients {
dc := c.GetBase().DialConf
sc.Dial = append(sc.Dial, dc)
}
for _, s := range allServers {
lc := s.GetBase().ListenConf
sc.Listen = append(sc.Listen, lc)
}
return
}
//cli.go 中定义的 CliCmd都是需进一步交互的命令
cliCmdList = append(cliCmdList, CliCmd{
"对当前引用的配置文件生成分享链接", func() {
"【生成分享链接】<-当前的配置", func() {
sc := getStandardConfFromCurrentState()
interactively_generate_share(&sc)
},
}, CliCmd{
"交互生成配置,超级强大", func() {
generateConfigFileInteractively()
},
"交互生成配置,超级强大", generateConfigFileInteractively,
}, CliCmd{
"热删除配置", func() {
interactively_hotRemoveServerOrClient()
},
"热删除配置", interactively_hotRemoveServerOrClient,
}, CliCmd{
"热加载新配置文件", func() {
interactively_hotLoadConfigFile()
},
"热加载新配置文件", interactively_hotLoadConfigFile,
}, CliCmd{
"调节日志等级", func() {
interactively_adjust_loglevel()
},
"【热加载】新配置url", interactively_hotLoadUrlConfig,
}, CliCmd{
"调节日志等级", interactively_adjust_loglevel,
})
}
@@ -446,6 +379,100 @@ func interactively_hotRemoveServerOrClient() {
printAllState(os.Stdout, true)
}
func interactively_hotLoadUrlConfig() {
utils.PrintStr("即将开始热添加url配置\n")
Select := promptui.Select{
Label: "请选择你的url的格式类型",
Items: []string{
"协议官方url格式(视代理协议不同而不同)",
"vs标准url格式",
},
}
i, result, err := Select.Run()
if err != nil {
fmt.Printf("Prompt failed %v\n", err)
return
}
fmt.Printf("你选择了 %s\n", result)
switch i {
case 0:
fmt.Printf("目前暂不支持")
return
case 1:
Select := promptui.Select{
Label: "请选择该url是用于服务端还是客户端",
Items: []string{
"客户端",
"服务端",
},
}
i, result, err := Select.Run()
if err != nil {
fmt.Printf("Prompt failed %v\n", err)
return
}
fmt.Printf("你选择了 %s\n", result)
fmt.Printf("请输入你的配置url\n")
var theUrlStr string
fmt.Scanln(&theUrlStr)
if err != nil {
fmt.Printf("Prompt failed %v\n", err)
return
}
if i == 0 {
u, sn, _, okTls, err := proxy.GetRealProtocolFromClientUrl(theUrlStr)
if err != nil {
fmt.Printf("parse url failed %v\n", err)
return
}
dc := &proxy.DialConf{}
dc.Protocol = sn
dc.TLS = okTls
err = proxy.URLToDialConf(u, dc)
if err != nil {
fmt.Printf("parse url failed %v\n", err)
return
}
hotLoadDialConfForRuntime("", []*proxy.DialConf{dc})
} else {
u, sn, _, okTls, err := proxy.GetRealProtocolFromServerUrl(theUrlStr)
if err != nil {
fmt.Printf("parse url failed %v\n", err)
return
}
lc := &proxy.ListenConf{}
lc.Protocol = sn
lc.TLS = okTls
err = proxy.URLToListenConf(u, lc)
if err != nil {
fmt.Printf("parse url failed %v\n", err)
return
}
hotLoadListenConfForRuntime([]*proxy.ListenConf{lc})
}
return
}
}
//热添加配置文件
func interactively_hotLoadConfigFile() {
utils.PrintStr("即将开始热添加配置文件\n")

View File

@@ -34,6 +34,15 @@ func interactively_generate_share(conf *proxy.StandardConf) {
}
},
},
{
Name: "vs标准toml",
f: func() {
fmt.Println("#vs_auto_generated:")
fmt.Println(utils.GetPurgedTomlStr(conf))
},
},
{
Name: "xray分享链接标准提案 (#716)",
f: func() {

View File

@@ -9,6 +9,7 @@ import (
"os"
httpProxy "github.com/e1732a364fed/v2ray_simple/proxy/http"
"github.com/e1732a364fed/v2ray_simple/tlsLayer"
vs "github.com/e1732a364fed/v2ray_simple"
"go.uber.org/zap"
@@ -29,36 +30,55 @@ var (
download bool
)
type CliCmd struct {
Name string
f func()
}
func (cc CliCmd) String() string {
return cc.Name
}
// func nlist(list []CliCmd) (result []string) {
// for _, v := range list {
// result = append(result, v.Name)
// }
// return
// }
func flist(list []CliCmd) (result []func()) {
for _, v := range list {
result = append(result, v.f)
}
return
}
// cliCmdList 包含所有交互模式中可执行的命令;
//本文件 中添加的 CliCmd都是直接返回运行结果的、无需进一步交互的命令
var cliCmdList = []CliCmd{
{
"查询当前状态", func() {
printAllState(os.Stdout, false)
},
}, {
"打印当前版本所支持的所有协议", printSupportedProtocols,
}, {
"生成随机ssl证书", generateRandomSSlCert,
}, {
"生成一个随机的uuid供你参考", generateAndPrintUUID,
}, {
"下载geosite文件夹", tryDownloadGeositeSource,
}, {
"下载geoip文件(GeoLite2-Country.mmdb)", tryDownloadMMDB,
},
}
func init() {
flag.BoolVar(&cmdPrintSupportedProtocols, "sp", false, "print supported protocols")
flag.BoolVar(&cmdPrintVer, "v", false, "print the version string then exit")
flag.BoolVar(&interactive_mode, "i", false, "enable interactive commandline mode")
flag.BoolVar(&download, "d", false, " automatically download required mmdb file")
//本文件 中定义的 CliCmd都是直接返回运行结果的、无需进一步交互的命令
cliCmdList = append(cliCmdList, CliCmd{
"生成一个随机的uuid供你参考", func() {
generateAndPrintUUID()
},
}, CliCmd{
"下载geosite文件夹", func() {
tryDownloadGeositeSource()
},
}, CliCmd{
"下载geoip文件(GeoLite2-Country.mmdb)", func() {
tryDownloadMMDB()
},
}, CliCmd{
"打印当前版本所支持的所有协议", func() {
printSupportedProtocols()
},
}, CliCmd{
"查询当前状态", func() {
printAllState(os.Stdout, false)
},
})
}
//运行一些 执行后立即退出程序的 命令
@@ -90,6 +110,38 @@ func generateAndPrintUUID() {
fmt.Printf("New random uuid : %s\n", utils.GenerateUUIDStr())
}
func generateRandomSSlCert() {
const certFn = "cert.pem"
const keyFn = "cert.key"
if utils.FileExist(certFn) {
utils.PrintStr(certFn)
utils.PrintStr(" 已存在!\n")
return
}
if utils.FileExist(keyFn) {
utils.PrintStr(keyFn)
utils.PrintStr(" 已存在!\n")
return
}
err := tlsLayer.GenerateRandomCertKeyFiles(certFn, keyFn)
if err == nil {
utils.PrintStr("生成成功!请查看目录中的 ")
utils.PrintStr(certFn)
utils.PrintStr(" 和 ")
utils.PrintStr(keyFn)
utils.PrintStr("\n")
} else {
utils.PrintStr("生成失败,")
utils.PrintStr(err.Error())
utils.PrintStr("\n")
}
}
func printSupportedProtocols() {
utils.PrintStr("Support tcp/udp/tproxy/unix domain socket/tls/uTls by default.\n")
proxy.PrintAllServerNames()
@@ -259,6 +311,10 @@ func hotLoadDialConfForRuntime(Default_uuid string, conf []*proxy.DialConf) {
}
func hotLoadListenConfForRuntime(conf []*proxy.ListenConf) {
if defaultOutClient == nil {
defaultOutClient = vs.DirectClient
}
for i, l := range conf {
inServer, err := proxy.NewServer(l)
if err != nil {

View File

@@ -14,11 +14,12 @@ package configAdapter
import (
"net/url"
"strconv"
"strings"
"github.com/e1732a364fed/v2ray_simple/proxy"
)
//convert proxy.DialConf to verysimple's official URL format.
//convert proxy.DialConf to verysimple Official URL format.
// See https://github.com/e1732a364fed/v2ray_simple/discussions/163
func ToVS(cc *proxy.CommonConf, dc *proxy.DialConf) string {
var u url.URL
@@ -71,15 +72,9 @@ func ToVS(cc *proxy.CommonConf, dc *proxy.DialConf) string {
q.Add("http.version", r.Version)
}
for k, v := range r.Headers {
vstr := ""
for i, v2 := range v {
vstr += v2
if i != len(v)-1 {
vstr += ", "
}
}
q.Add("header."+k, vstr)
for k, headers := range r.Headers {
q.Add("header."+k, strings.Join(headers, ", "))
}
}
}

View File

@@ -11,10 +11,12 @@ import (
)
/*
To Quantumult X [server_local] string
quantumult X 只支持 vmess,trojan,shadowsocks,http 这四种协议.
See https://github.com/crossutility/Quantumult-X/blob/master/sample.conf
圈叉的配置很奇葩,每一个协议的格式都略有不同,我们只能照着示例分情况处理。
圈叉的配置,每一个协议的格式都略有不同,我们只能照着示例分情况处理。
同时,我们不支持里面的 fast-open 等选项。
*/
@@ -175,7 +177,7 @@ func ToQX(dc *proxy.DialConf) string {
return sb.String()
}
/* clash使用yaml作为配置格式。我们该函数中不导出整个yaml配置文件而只导出
/* clash使用yaml作为配置格式。函数中不导出整个yaml配置文件而只导出
对应的proxies项下的子项比如
@@ -374,7 +376,6 @@ func ToClash(dc *proxy.DialConf) string {
return sb.String()
}
//See https://github.com/2dust/v2rayN/wiki/%E5%88%86%E4%BA%AB%E9%93%BE%E6%8E%A5%E6%A0%BC%E5%BC%8F%E8%AF%B4%E6%98%8E(ver-2)
type V2rayNConfig struct {
V string `json:"v"` //配置文件版本号,主要用来识别当前配置
PS string `json:"ps"` //备注或别名
@@ -390,6 +391,7 @@ type V2rayNConfig struct {
Sni string `json:"sni"`
}
//See https://github.com/2dust/v2rayN/wiki/%E5%88%86%E4%BA%AB%E9%93%BE%E6%8E%A5%E6%A0%BC%E5%BC%8F%E8%AF%B4%E6%98%8E(ver-2)
func ToV2rayN(dc *proxy.DialConf) string {
if dc.Protocol != "vmess" {
return "ToV2rayN doesn't support any protocol other than vmess, you give " + dc.Protocol

268
proxy/config_url.go Normal file
View File

@@ -0,0 +1,268 @@
package proxy
import (
"net"
"net/url"
"strconv"
"strings"
"github.com/e1732a364fed/v2ray_simple/httpLayer"
"github.com/e1732a364fed/v2ray_simple/utils"
)
const (
UrlNativeFormat = iota //proxy对应的标准文档所定义的url模式一般散布于对应github的文档上
UrlStandardFormat //VS定义的 供 所有proxy 使用的 标准 url模式
)
var (
// Url格式 设置以何种方式解析 命令行模式/极简模式 中出现的url配置
//
//关于url格式的详细 见 https://github.com/e1732a364fed/v2ray_simple/discussions/163
UrlFormat = UrlStandardFormat
)
//try find from map, trim tail s if necessary
func GetRealProtocolFromClientUrl(s string) (u *url.URL, schemeName string, creator ClientCreator, okTls bool, err error) {
u, err = url.Parse(s)
if err != nil {
err = utils.ErrInErr{ErrDesc: "Can't parse client url", ErrDetail: err, Data: s}
return
}
schemeName = strings.ToLower(u.Scheme)
var ok bool
creator, ok = clientCreatorMap[schemeName]
if !ok {
schemeName = strings.TrimSuffix(schemeName, "s")
creator, okTls = clientCreatorMap[schemeName]
if okTls {
ok = true
}
}
if !ok {
err = utils.ErrInErr{ErrDesc: "Unknown client protocol ", Data: u.Scheme}
}
return
}
//try find from map, trim tail s if necessary
func GetRealProtocolFromServerUrl(s string) (u *url.URL, schemeName string, creator ServerCreator, okTls bool, err error) {
u, err = url.Parse(s)
if err != nil {
err = utils.ErrInErr{ErrDesc: "Can't parse server url", ErrDetail: err, Data: s}
return
}
schemeName = strings.ToLower(u.Scheme)
var ok bool
creator, ok = serverCreatorMap[schemeName]
if !ok {
schemeName = strings.TrimSuffix(schemeName, "s")
creator, okTls = serverCreatorMap[schemeName]
if okTls {
ok = true
}
}
if !ok {
err = utils.ErrInErr{ErrDesc: "Unknown server protocol ", Data: u.Scheme}
}
return
}
// ClientFromURL calls the registered creator to create client. The returned bool is true if has err.
func ClientFromURL(s string) (Client, error) {
u, sn, creator, okTls, err := GetRealProtocolFromClientUrl(s)
if err != nil {
return nil, err
}
var dc *DialConf
if UrlFormat == UrlStandardFormat {
dc = &DialConf{}
dc.TLS = okTls
dc.Protocol = sn
e := URLToDialConf(u, dc)
if e != nil {
return nil, e
}
}
var e error
dc, e = creator.URLToDialConf(u, dc, UrlFormat)
if e != nil {
return nil, e
}
c, e := newClient(creator, dc, false)
if e != nil {
return nil, e
}
return c, nil
}
// ServerFromURL calls the registered creator to create proxy servers.
func ServerFromURL(s string) (Server, error) {
u, sn, creator, okTls, err := GetRealProtocolFromServerUrl(s)
if err != nil {
return nil, err
}
var lc *ListenConf
if UrlFormat == UrlStandardFormat {
lc = &ListenConf{}
lc.TLS = okTls
lc.Protocol = sn
e := URLToListenConf(u, lc)
if e != nil {
return nil, e
}
}
lc, err = creator.URLToListenConf(u, lc, UrlFormat)
if err != nil {
return nil, utils.ErrInErr{
ErrDesc: "URLToListenConf err ",
ErrDetail: err,
Data: s,
}
}
return newServer(creator, lc, false)
}
//setup conf with vs standard url format
func URLToCommonConf(u *url.URL, conf *CommonConf) error {
if u.Scheme != DirectName {
hn := u.Hostname()
ip := net.ParseIP(hn)
if ip != nil {
conf.IP = hn
} else {
conf.Host = hn
}
if hn != u.Host { //给出了port
colon := strings.LastIndexByte(u.Host, ':')
p, err := strconv.Atoi(u.Host[colon+1:])
if err != nil {
return err
} else if p < 0 || p > 65535 {
return utils.ErrInvalidData
}
conf.Port = p
}
}
q := u.Query()
conf.Network = q.Get("network")
conf.Fullcone = utils.QueryPositive(q, "fullcone")
conf.Tag = u.Fragment
conf.Path = u.Path
conf.AdvancedLayer = q.Get("adv")
conf.EncryptAlgo = q.Get("security")
if q.Get("v") != "" {
v, e := strconv.Atoi(q.Get("v"))
if e != nil {
return e
}
conf.Version = v
}
if utils.QueryPositive(q, "http") {
conf.HttpHeader = &httpLayer.HeaderPreset{}
}
return nil
}
func setHeaders(rawq, headers map[string][]string) {
for k, list := range rawq {
if strings.HasPrefix(k, "header.") && len(list) > 0 {
k = strings.TrimPrefix(k, "header.")
headers[k] = list
}
}
}
//setup conf with vs standard URL format
func URLToDialConf(u *url.URL, conf *DialConf) error {
e := URLToCommonConf(u, &conf.CommonConf)
q := u.Query()
if conf.HttpHeader != nil {
rh := &httpLayer.RequestHeader{
Method: q.Get("http.method"),
Version: q.Get("http.version"),
Path: []string{conf.Path},
Headers: map[string][]string{},
}
setHeaders(q, rh.Headers)
conf.HttpHeader.Request = rh
}
if conf.TLS {
conf.Insecure = utils.QueryPositive(q, "insecure")
conf.Utls = utils.QueryPositive(q, "utls")
}
return e
}
//setup conf with vs standard URL format
func URLToListenConf(u *url.URL, conf *ListenConf) error {
e := URLToCommonConf(u, &conf.CommonConf)
q := u.Query()
conf.NoRoute = utils.QueryPositive(q, "noroute")
conf.Fallback = q.Get("fallback")
if conf.HttpHeader != nil {
rh := &httpLayer.ResponseHeader{
StatusCode: q.Get("http.status_code"),
Version: q.Get("http.version"),
Reason: q.Get("http.reason"),
Headers: map[string][]string{},
}
setHeaders(q, rh.Headers)
conf.HttpHeader.Response = rh
}
if conf.TLS {
conf.Insecure = utils.QueryPositive(q, "insecure")
certFile := q.Get("cert")
keyFile := q.Get("key")
conf.TLSCert = certFile
conf.TLSKey = keyFile
}
return e
}

View File

@@ -40,6 +40,7 @@ type ClientCreator interface {
//大部分通用内容都会被proxy包解析方法只需要处理proxy包未知的内容
NewClient(*DialConf) (Client, error) //标准配置
//URLToDialConf 执行proxy自定义的非标准代码;
//iv: initial value, can be nil.
URLToDialConf(url *url.URL, iv *DialConf, format int) (*DialConf, error)
//DialConfToURL(url *DialConf, format int) (*url.URL, error)

View File

@@ -1,221 +0,0 @@
package proxy
import (
"net"
"net/url"
"strconv"
"strings"
"github.com/e1732a364fed/v2ray_simple/utils"
)
const (
UrlNativeFormat = iota //proxy对应的标准文档所定义的url模式一般散布于对应github的文档上
UrlStandardFormat //VS定义的 供 所有proxy 使用的 标准 url模式
)
var (
// Url格式 设置以何种方式解析 命令行模式/极简模式 中出现的url配置
//
//关于url格式的详细 见 https://github.com/e1732a364fed/v2ray_simple/discussions/163
UrlFormat = UrlStandardFormat
)
// ClientFromURL calls the registered creator to create client. The returned bool is true if has err.
func ClientFromURL(s string) (Client, error) {
u, err := url.Parse(s)
if err != nil {
return nil, utils.ErrInErr{ErrDesc: "Can't parse client url", ErrDetail: err, Data: s}
}
schemeName := strings.ToLower(u.Scheme)
creator, ok := clientCreatorMap[schemeName]
var okTls bool
if !ok {
realScheme := strings.TrimSuffix(schemeName, "s")
creator, okTls = clientCreatorMap[realScheme]
}
//尝试判断是否套tls, 比如vlesss实际上是vless+tlshttps实际上是http+tls
if okTls {
ok = true
}
if ok {
var dc *DialConf
if UrlFormat == UrlStandardFormat {
dc = &DialConf{}
setConfByStandardURL(&dc.CommonConf, u)
if okTls {
dc.TLS = true
setTLS_forConf_withStandardURL(u, &dc.CommonConf, nil, dc)
}
}
var e error
dc, e = creator.URLToDialConf(u, dc, UrlFormat)
if e != nil {
return nil, e
}
c, e := newClient(creator, dc, false)
if e != nil {
return nil, e
}
return c, nil
}
return nil, utils.ErrInErr{ErrDesc: "Unknown client protocol ", Data: u.Scheme}
}
// ServerFromURL calls the registered creator to create proxy servers.
func ServerFromURL(s string) (Server, error) {
u, err := url.Parse(s)
if err != nil {
return nil, utils.ErrInErr{
ErrDesc: "Can't parse server url ",
ErrDetail: err,
Data: s,
}
}
schemeName := strings.ToLower(u.Scheme)
creator, ok := serverCreatorMap[schemeName]
var okTls bool
if !ok {
realScheme := strings.TrimSuffix(schemeName, "s")
creator, okTls = serverCreatorMap[realScheme]
}
if okTls {
ok = true
}
if ok {
var sConf *ListenConf
if UrlFormat == UrlStandardFormat {
sConf = &ListenConf{}
confQueryForServer(sConf, u)
if okTls {
sConf.TLS = true
setTLS_forConf_withStandardURL(u, &sConf.CommonConf, sConf, nil)
}
}
sConf, err := creator.URLToListenConf(u, sConf, UrlFormat)
if err != nil {
return nil, utils.ErrInErr{
ErrDesc: "URLToListenConf err ",
ErrDetail: err,
Data: s,
}
}
return newServer(creator, sConf, false)
}
return nil, utils.ErrInErr{ErrDesc: "Unknown server protocol ", Data: u.Scheme}
}
func getFullconeFromUrl(url *url.URL) bool {
nStr := url.Query().Get("fullcone")
return nStr == "true" || nStr == "1"
}
//SetAddrStr, setNetwork, Isfullcone
func setConfByStandardURL(conf *CommonConf, u *url.URL) error {
if u.Scheme != DirectName {
hn := u.Hostname()
ip := net.ParseIP(hn)
if ip != nil {
conf.IP = hn
} else {
conf.Host = hn
}
if hn != u.Host { //给出了port
colon := strings.LastIndexByte(u.Host, ':')
p, err := strconv.Atoi(u.Host[colon+1:])
if err != nil {
return err
} else if p < 0 || p > 65535 {
return utils.ErrInvalidData
}
conf.Port = p
}
}
conf.Network = u.Query().Get("network")
conf.Fullcone = getFullconeFromUrl(u)
conf.Tag = u.Fragment
return nil
}
//set Tag, NoRoute,Fallback, call setConfByStandardURL
func confQueryForServer(conf *ListenConf, u *url.URL) {
nr := false
q := u.Query()
if q.Get("noroute") != "" {
nr = true
}
setConfByStandardURL(&conf.CommonConf, u)
conf.NoRoute = nr
conf.Tag = u.Fragment
fallbackStr := q.Get("fallback")
conf.Fallback = fallbackStr
}
//给 ProxyCommon 的tls做一些配置上的准备从url读取配置
func setTLS_forConf_withStandardURL(u *url.URL, com *CommonConf, lc *ListenConf, dc *DialConf) error {
q := u.Query()
insecureStr := q.Get("insecure")
if insecureStr != "" && insecureStr != "false" && insecureStr != "0" {
com.Insecure = true
}
if dc != nil {
utlsStr := q.Get("utls")
useUtls := utlsStr != "" && utlsStr != "false" && utlsStr != "0"
dc.Utls = useUtls
} else {
certFile := q.Get("cert")
keyFile := q.Get("key")
lc.TLSCert = certFile
lc.TLSKey = keyFile
}
return nil
}

View File

@@ -3,6 +3,7 @@ package utils
import (
"flag"
"net/url"
"os"
"strings"
@@ -85,3 +86,13 @@ func WrapFuncForPromptUI(f func(string) bool) func(string) error {
return ErrInvalidData
}
}
func QueryPositive(query url.Values, key string) bool {
nStr := query.Get(key)
return nStr == "true" || nStr == "1"
}
func QueryNegative(query url.Values, key string) bool {
nStr := query.Get(key)
return nStr == "false" || nStr == "0"
}