feat/fix: support allow_insecure and fix ws path with query

This commit is contained in:
mzz2017 2023-02-12 17:17:51 +08:00
parent 16a85e3c68
commit 7656a6ecaf
11 changed files with 86 additions and 56 deletions

View File

@ -353,3 +353,11 @@ func GetTagFromLinkLikePlaintext(link string) (tag string, afterTag string) {
// Else tag is the part before colon.
return link[:iColon], link[iColon+1:]
}
func BoolToString(b bool) string {
if b {
return "1"
} else {
return "0"
}
}

View File

@ -39,10 +39,11 @@ type GlobalOption struct {
CheckInterval time.Duration
CheckTolerance time.Duration
CheckDnsTcp bool
AllowInsecure bool
}
type InstanceOption struct {
CheckEnabled bool
CheckEnabled bool
}
type AliveDialerSetSet map[*AliveDialerSet]int

View File

@ -3,6 +3,7 @@ package http
import (
"fmt"
"github.com/mzz2017/softwind/protocol/http"
"github.com/v2rayA/dae/common"
"github.com/v2rayA/dae/component/outbound/dialer"
"net"
"net/url"
@ -15,24 +16,25 @@ func init() {
}
type HTTP struct {
Name string `json:"name"`
Server string `json:"server"`
Port int `json:"port"`
Username string `json:"username"`
Password string `json:"password"`
SNI string `json:"sni"`
Protocol string `json:"protocol"`
Name string `json:"name"`
Server string `json:"server"`
Port int `json:"port"`
Username string `json:"username"`
Password string `json:"password"`
SNI string `json:"sni"`
Protocol string `json:"protocol"`
AllowInsecure bool `json:"allowInsecure"`
}
func NewHTTP(option *dialer.GlobalOption, iOption dialer.InstanceOption, link string) (*dialer.Dialer, error) {
s, err := ParseHTTPURL(link)
s, err := ParseHTTPURL(link, option)
if err != nil {
return nil, fmt.Errorf("%w: %v", dialer.InvalidParameterErr, err)
}
return s.Dialer(option, iOption)
}
func ParseHTTPURL(link string) (data *HTTP, err error) {
func ParseHTTPURL(link string, option *dialer.GlobalOption) (data *HTTP, err error) {
u, err := url.Parse(link)
if err != nil || (u.Scheme != "http" && u.Scheme != "https") {
return nil, fmt.Errorf("%w: %v", dialer.InvalidParameterErr, err)
@ -51,13 +53,14 @@ func ParseHTTPURL(link string) (data *HTTP, err error) {
return nil, fmt.Errorf("error when parsing port: %w", err)
}
return &HTTP{
Name: u.Fragment,
Server: u.Hostname(),
Port: port,
Username: u.User.Username(),
Password: pwd,
SNI: u.Query().Get("sni"),
Protocol: u.Scheme,
Name: u.Fragment,
Server: u.Hostname(),
Port: port,
Username: u.User.Username(),
Password: pwd,
SNI: u.Query().Get("sni"),
Protocol: u.Scheme,
AllowInsecure: option.AllowInsecure,
}, nil
}
@ -67,7 +70,7 @@ func (s *HTTP) Dialer(option *dialer.GlobalOption, iOption dialer.InstanceOption
if err != nil {
return nil, err
}
return dialer.NewDialer(d, option, iOption, s.Name, s.Protocol, u.String()), nil
return dialer.NewDialer(d, option, iOption, s.Name, s.Protocol, u.String()), nil
}
func (s *HTTP) URL() url.URL {
@ -77,7 +80,7 @@ func (s *HTTP) URL() url.URL {
Fragment: s.Name,
}
if s.SNI != "" {
u.RawQuery = url.Values{"sni": []string{s.SNI}}.Encode()
u.RawQuery = url.Values{"sni": []string{s.SNI}, "allowInsecure": []string{common.BoolToString(s.AllowInsecure)}}.Encode()
}
if s.Username != "" {
if s.Password != "" {

View File

@ -35,7 +35,7 @@ type Trojan struct {
}
func NewTrojan(option *dialer.GlobalOption, iOption dialer.InstanceOption, link string) (*dialer.Dialer, error) {
s, err := ParseTrojanURL(link)
s, err := ParseTrojanURL(link, option)
if err != nil {
return nil, err
}
@ -48,7 +48,8 @@ func (s *Trojan) Dialer(option *dialer.GlobalOption, iOption dialer.InstanceOpti
Scheme: "tls",
Host: net.JoinHostPort(s.Server, strconv.Itoa(s.Port)),
RawQuery: url.Values{
"sni": []string{s.Sni},
"sni": []string{s.Sni},
"allowInsecure": []string{common.BoolToString(s.AllowInsecure)},
}.Encode(),
}
var err error
@ -65,8 +66,8 @@ func (s *Trojan) Dialer(option *dialer.GlobalOption, iOption dialer.InstanceOpti
Scheme: "ws",
Host: net.JoinHostPort(s.Server, strconv.Itoa(s.Port)),
RawQuery: url.Values{
"host": []string{s.Host},
"path": []string{s.Path},
"host": []string{s.Host},
"path": []string{s.Path},
}.Encode(),
}
if d, err = ws.NewWs(u.String(), d); err != nil {
@ -78,9 +79,10 @@ func (s *Trojan) Dialer(option *dialer.GlobalOption, iOption dialer.InstanceOpti
serviceName = "GunService"
}
d = &grpc.Dialer{
NextDialer: &protocol.DialerConverter{Dialer: d},
ServiceName: serviceName,
ServerName: s.Sni,
NextDialer: &protocol.DialerConverter{Dialer: d},
ServiceName: serviceName,
ServerName: s.Sni,
AllowInsecure: s.AllowInsecure,
}
}
if strings.HasPrefix(s.Encryption, "ss;") {
@ -101,17 +103,20 @@ func (s *Trojan) Dialer(option *dialer.GlobalOption, iOption dialer.InstanceOpti
}); err != nil {
return nil, err
}
return dialer.NewDialer(d, option, iOption, s.Name, s.Protocol, s.ExportToURL()), nil
return dialer.NewDialer(d, option, iOption, s.Name, s.Protocol, s.ExportToURL()), nil
}
func ParseTrojanURL(u string) (data *Trojan, err error) {
func ParseTrojanURL(u string, option *dialer.GlobalOption) (data *Trojan, err error) {
//trojan://password@server:port#escape(remarks)
t, err := url.Parse(u)
if err != nil {
err = fmt.Errorf("invalid trojan format")
return
}
allowInsecure := t.Query().Get("allowInsecure")
allowInsecure, _ := strconv.ParseBool(t.Query().Get("allowInsecure"))
if !allowInsecure && option.AllowInsecure {
allowInsecure = true
}
sni := t.Query().Get("peer")
if sni == "" {
sni = t.Query().Get("sni")
@ -129,7 +134,7 @@ func ParseTrojanURL(u string) (data *Trojan, err error) {
Port: port,
Password: t.User.Username(),
Sni: sni,
AllowInsecure: allowInsecure == "1" || allowInsecure == "true",
AllowInsecure: allowInsecure,
Protocol: "trojan",
}
if t.Query().Get("type") != "" {
@ -145,7 +150,6 @@ func ParseTrojanURL(u string) (data *Trojan, err error) {
if data.Type == "grpc" && data.ServiceName == "" {
data.ServiceName = data.Path
}
data.AllowInsecure = false
}
return data, nil
}

View File

@ -48,7 +48,7 @@ func NewV2Ray(option *dialer.GlobalOption, iOption dialer.InstanceOption, link s
)
switch {
case strings.HasPrefix(link, "vmess://"):
s, err = ParseVmessURL(link)
s, err = ParseVmessURL(link, option)
if err != nil {
return nil, err
}
@ -56,7 +56,7 @@ func NewV2Ray(option *dialer.GlobalOption, iOption dialer.InstanceOption, link s
return nil, fmt.Errorf("%w: aid: %v, we only support AEAD encryption", dialer.UnexpectedFieldErr, s.Aid)
}
case strings.HasPrefix(link, "vless://"):
s, err = ParseVlessURL(link)
s, err = ParseVlessURL(link, option)
if err != nil {
return nil, err
}
@ -92,8 +92,9 @@ func (s *V2Ray) Dialer(option *dialer.GlobalOption, iOption dialer.InstanceOptio
Host: net.JoinHostPort(s.Add, s.Port),
Path: s.Path,
RawQuery: url.Values{
"host": []string{s.Host},
"sni": []string{sni},
"host": []string{s.Host},
"sni": []string{sni},
"allowInsecure": []string{common.BoolToString(s.AllowInsecure)},
}.Encode(),
}
d, err = ws.NewWs(u.String(), d)
@ -110,7 +111,8 @@ func (s *V2Ray) Dialer(option *dialer.GlobalOption, iOption dialer.InstanceOptio
Scheme: "tls",
Host: net.JoinHostPort(s.Add, s.Port),
RawQuery: url.Values{
"sni": []string{sni},
"sni": []string{sni},
"allowInsecure": []string{common.BoolToString(s.AllowInsecure)},
}.Encode(),
}
d, err = tls.NewTls(u.String(), d)
@ -131,9 +133,10 @@ func (s *V2Ray) Dialer(option *dialer.GlobalOption, iOption dialer.InstanceOptio
serviceName = "GunService"
}
d = &grpc.Dialer{
NextDialer: &protocol.DialerConverter{Dialer: d},
ServiceName: serviceName,
ServerName: sni,
NextDialer: &protocol.DialerConverter{Dialer: d},
ServiceName: serviceName,
ServerName: sni,
AllowInsecure: s.AllowInsecure,
}
default:
return nil, fmt.Errorf("%w: network: %v", dialer.UnexpectedFieldErr, s.Net)
@ -147,10 +150,10 @@ func (s *V2Ray) Dialer(option *dialer.GlobalOption, iOption dialer.InstanceOptio
}); err != nil {
return nil, err
}
return dialer.NewDialer(d, option, iOption, s.Ps, s.Protocol, s.ExportToURL()), nil
return dialer.NewDialer(d, option, iOption, s.Ps, s.Protocol, s.ExportToURL()), nil
}
func ParseVlessURL(vless string) (data *V2Ray, err error) {
func ParseVlessURL(vless string, option *dialer.GlobalOption) (data *V2Ray, err error) {
u, err := url.Parse(vless)
if err != nil {
return nil, err
@ -188,10 +191,13 @@ func ParseVlessURL(vless string) (data *V2Ray, err error) {
if data.Type == "mkcp" || data.Type == "kcp" {
data.Path = u.Query().Get("seed")
}
if option.AllowInsecure {
data.AllowInsecure = true
}
return data, nil
}
func ParseVmessURL(vmess string) (data *V2Ray, err error) {
func ParseVmessURL(vmess string, option *dialer.GlobalOption) (data *V2Ray, err error) {
var info V2Ray
// perform base64 decoding and unmarshal to VmessInfo
raw, err := common.Base64StdDecode(vmess[8:])
@ -265,6 +271,9 @@ func ParseVmessURL(vmess string) (data *V2Ray, err error) {
info.Aid = "0"
}
info.Protocol = "vmess"
if option.AllowInsecure {
info.AllowInsecure = true
}
return &info, nil
}

View File

@ -8,6 +8,7 @@ import (
"net"
"net/http"
"net/url"
"strconv"
)
// Ws is a base Ws struct
@ -40,18 +41,17 @@ func NewWs(s string, d proxy.Dialer) (*Ws, error) {
wsUrl := url.URL{
Scheme: u.Scheme,
Host: u.Host,
Path: u.Path,
}
t.wsAddr = wsUrl.String()
t.wsAddr = wsUrl.String() + u.Path
t.wsDialer = &websocket.Dialer{
NetDial: d.Dial,
NetDial: d.Dial,
//Subprotocols: []string{"binary"},
}
if u.Scheme == "wss" {
if u.Query().Get("sni") != "" {
t.wsDialer.TLSClientConfig = &tls.Config{
ServerName: u.Query().Get("sni"),
}
skipVerify, _ := strconv.ParseBool(u.Query().Get("allowInsecure"))
t.wsDialer.TLSClientConfig = &tls.Config{
ServerName: u.Query().Get("sni"),
InsecureSkipVerify: skipVerify,
}
}
return t, nil

View File

@ -18,10 +18,7 @@ type Global struct {
LogLevel string `mapstructure:"log_level" default:"info"`
// We use DirectTcpCheckUrl to check (tcp)*(ipv4/ipv6) connectivity for direct.
//DirectTcpCheckUrl string `mapstructure:"direct_tcp_check_url" default:"http://www.qualcomm.cn/generate_204"`
// We use TcpCheckUrl to check (tcp)*(ipv4/ipv6) connectivity for non-direct and non-DNS packets.
TcpCheckUrl string `mapstructure:"tcp_check_url" default:"http://cp.cloudflare.com"`
// We use UdpCheckDns to check (tcp/udp)*(ipv4/ipv6) connectivity for DNS packets,
// and udp*(ipv4/ipv6) connectivity for all other types of packets.
TcpCheckUrl string `mapstructure:"tcp_check_url" default:"http://cp.cloudflare.com"`
UdpCheckDns string `mapstructure:"udp_check_dns" default:"dns.google:53"`
CheckInterval time.Duration `mapstructure:"check_interval" default:"30s"`
CheckTolerance time.Duration `mapstructure:"check_tolerance" default:"0"`
@ -29,6 +26,7 @@ type Global struct {
LanInterface []string `mapstructure:"lan_interface"`
LanNatDirect bool `mapstructure:"lan_nat_direct" required:""`
WanInterface []string `mapstructure:"wan_interface"`
AllowInsecure bool `mapstructure:"allow_insecure" default:"false"`
}
type Group struct {

View File

@ -200,6 +200,9 @@ func NewControlPlane(
checkDnsTcp = true
}
}
if global.AllowInsecure {
log.Warnln("AllowInsecure is enabled, but it is not recommended. Please make sure you have to turn it on.")
}
option := &dialer.GlobalOption{
Log: log,
TcpCheckOptionRaw: dialer.TcpCheckOptionRaw{Raw: global.TcpCheckUrl},
@ -207,6 +210,7 @@ func NewControlPlane(
CheckInterval: global.CheckInterval,
CheckTolerance: global.CheckTolerance,
CheckDnsTcp: checkDnsTcp,
AllowInsecure: global.AllowInsecure,
}
outbounds := []*outbound.DialerGroup{
outbound.NewDialerGroup(option, consts.OutboundDirect.String(),

View File

@ -42,6 +42,9 @@ global {
# The WAN interface to bind. Use it if you want to proxy localhost.
# Multiple interfaces split by ",".
wan_interface: wlp5s0
# Allow insecure TLS certificates. It is not recommended to turn it on unless you have to.
allow_insecure: false
}
# Subscriptions defined here will be resolved as nodes and merged as a part of the global node pool.

2
go.mod
View File

@ -9,7 +9,7 @@ require (
github.com/gorilla/websocket v1.5.0
github.com/json-iterator/go v1.1.12
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
github.com/mzz2017/softwind v0.0.0-20230212082815-dee826918b06
github.com/mzz2017/softwind v0.0.0-20230212090240-561c250bc5c4
github.com/safchain/ethtool v0.0.0-20230116090318-67cc41908669
github.com/sirupsen/logrus v1.9.0
github.com/spf13/cobra v1.6.1

4
go.sum
View File

@ -69,8 +69,8 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/mzz2017/disk-bloom v1.0.1 h1:rEF9MiXd9qMW3ibRpqcerLXULoTgRlM21yqqJl1B90M=
github.com/mzz2017/disk-bloom v1.0.1/go.mod h1:JLHETtUu44Z6iBmsqzkOtFlRvXSlKnxjwiBRDapizDI=
github.com/mzz2017/softwind v0.0.0-20230212082815-dee826918b06 h1:cdXO7ciiP2ubeayuHQIWEK3eai/bNW4dAbNgyu8C558=
github.com/mzz2017/softwind v0.0.0-20230212082815-dee826918b06/go.mod h1:K1nXwtBokwEsfOfdT/5zV6R8QabGkyhcR0iuTrRZcYY=
github.com/mzz2017/softwind v0.0.0-20230212090240-561c250bc5c4 h1:f7nqFcMs8LaM/eLRHGeuMk/urv/U+AMNKjFylwowlwU=
github.com/mzz2017/softwind v0.0.0-20230212090240-561c250bc5c4/go.mod h1:K1nXwtBokwEsfOfdT/5zV6R8QabGkyhcR0iuTrRZcYY=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=