Provide a new implement way of shadowsocks plugin. (#604)

This commit is contained in:
Changwei Miao 2022-08-28 11:10:48 +08:00 committed by mzz2017
parent d35f5d99e0
commit e1a5f8cfe3
5 changed files with 201 additions and 8 deletions

3
.gitignore vendored
View File

@ -33,3 +33,6 @@ node_modules
/PKGBUILD /PKGBUILD
/go.mod /go.mod
/go.sum /go.sum
# Virtualenv
.env

View File

@ -289,6 +289,32 @@
<option value="v2ray-plugin">v2ray-plugin</option> <option value="v2ray-plugin">v2ray-plugin</option>
</b-select> </b-select>
</b-field> </b-field>
<b-field
v-if="ss.plugin === 'simple-obfs' || ss.plugin === 'v2ray-plugin'"
label-position="on-border"
class="with-icon-alert"
>
<template slot="label">
Impl
<b-tooltip
type="is-dark"
:label="$t('setting.messages.ssPluginImpl')"
multilined
position="is-right"
>
<b-icon
size="is-samll"
icon=" iconfont icon-help-circle-outline"
style="position:relative;top:2px;right:3px;font-weight:normal"
/>
</b-tooltip>
</template>
<b-select ref="ss_plugin_impl" v-model="ss.impl" expanded>
<option value="">{{ $t("setting.options.default") }}</option>
<option value="chained">chained</option>
<option value="transport">transport</option>
</b-select>
</b-field>
<b-field <b-field
v-show="ss.plugin === 'simple-obfs'" v-show="ss.plugin === 'simple-obfs'"
label="Obfs" label="Obfs"
@ -753,7 +779,8 @@ export default {
server: "", server: "",
port: "", port: "",
name: "", name: "",
protocol: "ss" protocol: "ss",
impl: ""
}, },
ssr: { ssr: {
method: "aes-128-cfb", method: "aes-128-cfb",
@ -936,7 +963,8 @@ export default {
name: u.hash, name: u.hash,
obfs: "http", obfs: "http",
plugin: "", plugin: "",
protocol: "ss" protocol: "ss",
impl: ""
}; };
if (u.params.plugin) { if (u.params.plugin) {
u.params.plugin = decodeURIComponent(u.params.plugin); u.params.plugin = decodeURIComponent(u.params.plugin);
@ -972,6 +1000,8 @@ export default {
break; break;
case "tls": case "tls":
obj.tls = "tls"; obj.tls = "tls";
case "impl":
obj.impl = a[1];
} }
} }
} }
@ -1159,12 +1189,18 @@ export default {
} }
plugin.push("path=" + srcObj.path); plugin.push("path=" + srcObj.path);
} }
if (srcObj.impl) {
plugin.push("impl=" + srcObj.impl);
}
} else { } else {
plugin.push("obfs=" + srcObj.obfs); plugin.push("obfs=" + srcObj.obfs);
plugin.push("obfs-host=" + srcObj.host); plugin.push("obfs-host=" + srcObj.host);
if (srcObj.obfs === "http") { if (srcObj.obfs === "http") {
plugin.push("obfs-path=" + srcObj.path); plugin.push("obfs-path=" + srcObj.path);
} }
if (srcObj.impl) {
plugin.push("impl=" + srcObj.impl);
}
} }
tmp += `?plugin=${encodeURIComponent(plugin.join(";"))}`; tmp += `?plugin=${encodeURIComponent(plugin.join(";"))}`;
} }

View File

@ -160,6 +160,10 @@ export default {
<p>TCP: {tcpPorts}</p> <p>TCP: {tcpPorts}</p>
<p>UDP: {udpPorts}</p>`, <p>UDP: {udpPorts}</p>`,
grpcShouldWithTls: `gRPC must be with TLS` grpcShouldWithTls: `gRPC must be with TLS`
ssPluginImpl:
"★default: 'transport' for simple-obfs, 'chained' for v2ray-plugin." +
"★chained: shadowsocks traffic will be redirect to standalone plugin." +
"★transport: processed by the transport layer of v2ray/xray core directly."
} }
}, },
customAddressPort: { customAddressPort: {

View File

@ -159,6 +159,10 @@ export default {
<p>TCP: {tcpPorts}</p> <p>TCP: {tcpPorts}</p>
<p>UDP: {udpPorts}</p>`, <p>UDP: {udpPorts}</p>`,
grpcShouldWithTls: `gRPC必须启用TLS` grpcShouldWithTls: `gRPC必须启用TLS`
ssPluginImpl:
"★默认:使用 simple-obfs 时为等效传输层v2ray-plugin 时为链式。" +
"★链式shadowsocks 流量会被转发至独立的插件。" +
"★等效传输层:直接由 v2ray/xray 核心的传输层处理。"
} }
}, },
customAddressPort: { customAddressPort: {

View File

@ -106,12 +106,7 @@ func ParseSSURL(u string) (data *Shadowsocks, err error) {
return v, nil return v, nil
} }
func (s *Shadowsocks) Configuration(info PriorInfo) (c Configuration, err error) { func (s *Shadowsocks) ConfigurationMC(info PriorInfo) (c Configuration, err error) {
switch s.Cipher {
case "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "plain", "none":
default:
return c, fmt.Errorf("unsupported shadowsocks encryption method: %v", s.Cipher)
}
v2rayServer := coreObj.Server{ v2rayServer := coreObj.Server{
Address: s.Server, Address: s.Server,
Port: s.Port, Port: s.Port,
@ -213,6 +208,148 @@ func (s *Shadowsocks) Configuration(info PriorInfo) (c Configuration, err error)
}, nil }, nil
} }
func (s *Shadowsocks) ConfigurationMT(info PriorInfo) (c Configuration, err error) {
v2rayServer := coreObj.Server{
Address: s.Server,
Port: s.Port,
Method: s.Cipher,
Password: s.Password,
}
udpSupport := true
var v2StreamSettings *coreObj.StreamSettings
var v2Mux *coreObj.Mux
switch s.Plugin.Name {
case "simple-obfs":
host := s.Plugin.Opts.Host
if host == "" {
host = "cloudflare.com"
}
path := s.Plugin.Opts.Path
if !strings.HasPrefix(path, "/") {
path = "/" + path
}
v2StreamSettings = &coreObj.StreamSettings{}
tcpSettings := coreObj.TCPSettings{
Header: coreObj.TCPHeader{
Type: "http",
Request: coreObj.HTTPRequest{
Version: "1.1",
Method: "GET",
Path: strings.Split(path, ","),
Headers: coreObj.HTTPReqHeader{
Host: strings.Split(host, ","),
UserAgent: []string{
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/527.36 (KHTML, like Gecko) Chrome/55.2883.75 Safari/537.36",
"Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.46",
},
AcceptEncoding: []string{"gzip, deflate"},
Connection: []string{"keep-alive"},
Pragma: "no-cache",
},
},
Response: coreObj.HTTPResponse{
Version: "1.1",
Status: "200",
Reason: "OK",
Headers: coreObj.HTTPRespHeader {
ContentType: []string{"application/octet-stream", "video/mpeg"},
TransferEncoding: []string{"chunked"},
Connection: []string{"keep-alive"},
Pragma: "no-cache",
},
},
},
}
switch s.Plugin.Opts.Obfs {
case "http":
v2StreamSettings.Network = "tcp"
v2StreamSettings.TCPSettings = &tcpSettings
case "tls":
v2StreamSettings.Security = "tls"
v2StreamSettings.TLSSettings = &coreObj.TLSSettings{}
// SNI
v2StreamSettings.TLSSettings.ServerName = host
default:
return c, fmt.Errorf("unsupported obfs %v of plugin %v", s.Plugin.Opts.Obfs, s.Plugin.Name)
}
case "v2ray-plugin":
v2StreamSettings = &coreObj.StreamSettings{}
host := s.Plugin.Opts.Host
if host == "" {
host = "cloudflare.com"
}
path := s.Plugin.Opts.Path
if !strings.HasPrefix(path, "/") {
path = "/" + path
}
if s.Plugin.Opts.Tls == "tls" {
v2StreamSettings.Security = "tls"
v2StreamSettings.TLSSettings = &coreObj.TLSSettings{}
// SNI
v2StreamSettings.TLSSettings.ServerName = host
}
v2Mux = &coreObj.Mux{
Enabled: true,
Concurrency: 1,
}
switch s.Plugin.Opts.Obfs {
case "quic":
return c, fmt.Errorf("quic is not yet supported")
default:
// "websocket" or ""
v2StreamSettings.Network = "ws"
v2StreamSettings.WsSettings = &coreObj.WsSettings{
Path: path,
Headers: coreObj.Headers{
Host: host,
},
}
}
case "":
// no plugin
default:
return c, fmt.Errorf("unsupported plugin %v", s.Plugin.Name)
}
return Configuration{
CoreOutbound: coreObj.OutboundObject{
Tag: info.Tag,
Protocol: "shadowsocks",
Settings: coreObj.Settings{
Servers: []coreObj.Server{v2rayServer},
},
StreamSettings: v2StreamSettings,
Mux: v2Mux,
},
UDPSupport: udpSupport,
}, nil
}
func (s *Shadowsocks) Configuration(info PriorInfo) (c Configuration, err error) {
switch s.Cipher {
case "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "plain", "none":
default:
return c, fmt.Errorf("unsupported shadowsocks encryption method: %v", s.Cipher)
}
// check shadowsocks plugin implementation
ssPluginImpl := s.Plugin.Opts.Impl
if ssPluginImpl == "" {
switch s.Plugin.Name {
case "simple-obfs":
ssPluginImpl = "transport"
default:
ssPluginImpl = "chained"
}
}
switch ssPluginImpl {
case "chained":
return s.ConfigurationMC(info)
case "transport":
return s.ConfigurationMT(info)
default:
return c, fmt.Errorf("unsupported shadowsocks plugin implementation: %v", ssPluginImpl)
}
}
func (s *Shadowsocks) ExportToURL() string { func (s *Shadowsocks) ExportToURL() string {
// sip002 // sip002
u := &url.URL{ u := &url.URL{
@ -273,6 +410,7 @@ type Sip003Opts struct {
Obfs string `json:"obfs"` Obfs string `json:"obfs"`
Host string `json:"host"` Host string `json:"host"`
Path string `json:"uri"` Path string `json:"uri"`
Impl string `json:"impl"`
} }
func ParseSip003Opts(opts string) Sip003Opts { func ParseSip003Opts(opts string) Sip003Opts {
@ -296,6 +434,8 @@ func ParseSip003Opts(opts string) Sip003Opts {
sip003Opts.Path = a[1] sip003Opts.Path = a[1]
case "obfs-host", "host": case "obfs-host", "host":
sip003Opts.Host = a[1] sip003Opts.Host = a[1]
case "impl":
sip003Opts.Impl = a[1]
} }
} }
return sip003Opts return sip003Opts
@ -326,6 +466,9 @@ func (s *Sip003) String() string {
if s.Opts.Path != "" { if s.Opts.Path != "" {
list = append(list, "obfs-uri="+s.Opts.Path) list = append(list, "obfs-uri="+s.Opts.Path)
} }
if s.Opts.Impl != "" {
list = append(list, "impl="+s.Opts.Impl)
}
case "v2ray-plugin": case "v2ray-plugin":
if s.Opts.Tls != "" { if s.Opts.Tls != "" {
list = append(list, "tls") list = append(list, "tls")
@ -339,6 +482,9 @@ func (s *Sip003) String() string {
if s.Opts.Path != "" { if s.Opts.Path != "" {
list = append(list, "path="+s.Opts.Path) list = append(list, "path="+s.Opts.Path)
} }
if s.Opts.Impl != "" {
list = append(list, "impl="+s.Opts.Impl)
}
} }
return strings.Join(list, ";") return strings.Join(list, ";")
} }