mirror of
https://github.com/daeuniverse/dae.git
synced 2025-07-13 17:29:09 +07:00
feat: support juicity (#248)
* feat: support juicity * optimize(juicity): lower reserved streams * fix(juicity): support to detach from client pool * docs: add docs * fix(trojan): udp * fix: panic if tuic and juice are both used --------- Co-authored-by: dae-bot[bot] <136105375+dae-bot[bot]@users.noreply.github.com>
This commit is contained in:
133
component/outbound/dialer/juicity/juicity.go
Normal file
133
component/outbound/dialer/juicity/juicity.go
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
package juicity
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/daeuniverse/dae/common"
|
||||||
|
"github.com/daeuniverse/dae/component/outbound/dialer"
|
||||||
|
"github.com/mzz2017/softwind/netproxy"
|
||||||
|
"github.com/mzz2017/softwind/protocol"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dialer.FromLinkRegister("juicity", NewJuice)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Juice struct {
|
||||||
|
Name string
|
||||||
|
Server string
|
||||||
|
Port int
|
||||||
|
User string
|
||||||
|
Password string
|
||||||
|
Sni string
|
||||||
|
AllowInsecure bool
|
||||||
|
CongestionControl string
|
||||||
|
Protocol string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewJuice(option *dialer.GlobalOption, nextDialer netproxy.Dialer, link string) (netproxy.Dialer, *dialer.Property, error) {
|
||||||
|
s, err := ParseJuiceURL(link)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return s.Dialer(option, nextDialer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Juice) Dialer(option *dialer.GlobalOption, nextDialer netproxy.Dialer) (netproxy.Dialer, *dialer.Property, error) {
|
||||||
|
d := nextDialer
|
||||||
|
var err error
|
||||||
|
var flags protocol.Flags
|
||||||
|
if d, err = protocol.NewDialer("juicity", d, protocol.Header{
|
||||||
|
ProxyAddress: net.JoinHostPort(s.Server, strconv.Itoa(s.Port)),
|
||||||
|
Feature1: s.CongestionControl,
|
||||||
|
TlsConfig: &tls.Config{
|
||||||
|
NextProtos: []string{"h3"},
|
||||||
|
MinVersion: tls.VersionTLS13,
|
||||||
|
ServerName: s.Sni,
|
||||||
|
InsecureSkipVerify: s.AllowInsecure || option.AllowInsecure,
|
||||||
|
},
|
||||||
|
User: s.User,
|
||||||
|
Password: s.Password,
|
||||||
|
IsClient: true,
|
||||||
|
Flags: flags,
|
||||||
|
}); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return d, &dialer.Property{
|
||||||
|
Name: s.Name,
|
||||||
|
Address: net.JoinHostPort(s.Server, strconv.Itoa(s.Port)),
|
||||||
|
Protocol: s.Protocol,
|
||||||
|
Link: s.ExportToURL(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseJuiceURL(u string) (data *Juice, err error) {
|
||||||
|
//trojan://password@server:port#escape(remarks)
|
||||||
|
t, err := url.Parse(u)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("invalid trojan format")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
allowInsecure, _ := strconv.ParseBool(t.Query().Get("allowInsecure"))
|
||||||
|
if !allowInsecure {
|
||||||
|
allowInsecure, _ = strconv.ParseBool(t.Query().Get("allow_insecure"))
|
||||||
|
}
|
||||||
|
if !allowInsecure {
|
||||||
|
allowInsecure, _ = strconv.ParseBool(t.Query().Get("allowinsecure"))
|
||||||
|
}
|
||||||
|
if !allowInsecure {
|
||||||
|
allowInsecure, _ = strconv.ParseBool(t.Query().Get("skipVerify"))
|
||||||
|
}
|
||||||
|
sni := t.Query().Get("peer")
|
||||||
|
if sni == "" {
|
||||||
|
sni = t.Query().Get("sni")
|
||||||
|
}
|
||||||
|
if sni == "" {
|
||||||
|
sni = t.Hostname()
|
||||||
|
}
|
||||||
|
disableSni, _ := strconv.ParseBool(t.Query().Get("disable_sni"))
|
||||||
|
if disableSni {
|
||||||
|
sni = ""
|
||||||
|
allowInsecure = true
|
||||||
|
}
|
||||||
|
port, err := strconv.Atoi(t.Port())
|
||||||
|
if err != nil {
|
||||||
|
return nil, dialer.InvalidParameterErr
|
||||||
|
}
|
||||||
|
password, _ := t.User.Password()
|
||||||
|
data = &Juice{
|
||||||
|
Name: t.Fragment,
|
||||||
|
Server: t.Hostname(),
|
||||||
|
Port: port,
|
||||||
|
User: t.User.Username(),
|
||||||
|
Password: password,
|
||||||
|
Sni: sni,
|
||||||
|
AllowInsecure: allowInsecure,
|
||||||
|
CongestionControl: t.Query().Get("congestion_control"),
|
||||||
|
Protocol: "juicity",
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Juice) ExportToURL() string {
|
||||||
|
u := &url.URL{
|
||||||
|
Scheme: "juicity",
|
||||||
|
User: url.UserPassword(t.User, t.Password),
|
||||||
|
Host: net.JoinHostPort(t.Server, strconv.Itoa(t.Port)),
|
||||||
|
Fragment: t.Name,
|
||||||
|
}
|
||||||
|
q := u.Query()
|
||||||
|
if t.AllowInsecure {
|
||||||
|
q.Set("allow_insecure", "1")
|
||||||
|
}
|
||||||
|
common.SetValue(&q, "sni", t.Sni)
|
||||||
|
if t.CongestionControl != "" {
|
||||||
|
common.SetValue(&q, "congestion_control", t.CongestionControl)
|
||||||
|
}
|
||||||
|
u.RawQuery = q.Encode()
|
||||||
|
return u.String()
|
||||||
|
}
|
@ -132,7 +132,7 @@ func ParseTuicURL(u string) (data *Tuic, err error) {
|
|||||||
|
|
||||||
func (t *Tuic) ExportToURL() string {
|
func (t *Tuic) ExportToURL() string {
|
||||||
u := &url.URL{
|
u := &url.URL{
|
||||||
Scheme: "trojan",
|
Scheme: "tuic",
|
||||||
User: url.UserPassword(t.User, t.Password),
|
User: url.UserPassword(t.User, t.Password),
|
||||||
Host: net.JoinHostPort(t.Server, strconv.Itoa(t.Port)),
|
Host: net.JoinHostPort(t.Server, strconv.Itoa(t.Port)),
|
||||||
Fragment: t.Name,
|
Fragment: t.Name,
|
||||||
|
@ -7,6 +7,7 @@ package outbound
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
_ "github.com/daeuniverse/dae/component/outbound/dialer/http"
|
_ "github.com/daeuniverse/dae/component/outbound/dialer/http"
|
||||||
|
_ "github.com/daeuniverse/dae/component/outbound/dialer/juicity"
|
||||||
_ "github.com/daeuniverse/dae/component/outbound/dialer/shadowsocks"
|
_ "github.com/daeuniverse/dae/component/outbound/dialer/shadowsocks"
|
||||||
_ "github.com/daeuniverse/dae/component/outbound/dialer/shadowsocksr"
|
_ "github.com/daeuniverse/dae/component/outbound/dialer/shadowsocksr"
|
||||||
_ "github.com/daeuniverse/dae/component/outbound/dialer/socks"
|
_ "github.com/daeuniverse/dae/component/outbound/dialer/socks"
|
||||||
@ -16,6 +17,7 @@ import (
|
|||||||
_ "github.com/daeuniverse/dae/component/outbound/transport/simpleobfs"
|
_ "github.com/daeuniverse/dae/component/outbound/transport/simpleobfs"
|
||||||
_ "github.com/daeuniverse/dae/component/outbound/transport/tls"
|
_ "github.com/daeuniverse/dae/component/outbound/transport/tls"
|
||||||
_ "github.com/daeuniverse/dae/component/outbound/transport/ws"
|
_ "github.com/daeuniverse/dae/component/outbound/transport/ws"
|
||||||
|
_ "github.com/mzz2017/softwind/protocol/juicity"
|
||||||
_ "github.com/mzz2017/softwind/protocol/shadowsocks"
|
_ "github.com/mzz2017/softwind/protocol/shadowsocks"
|
||||||
_ "github.com/mzz2017/softwind/protocol/trojanc"
|
_ "github.com/mzz2017/softwind/protocol/trojanc"
|
||||||
_ "github.com/mzz2017/softwind/protocol/tuic"
|
_ "github.com/mzz2017/softwind/protocol/tuic"
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
- [x] Trojan-gfw
|
- [x] Trojan-gfw
|
||||||
- [x] Trojan-go
|
- [x] Trojan-go
|
||||||
- [x] [Tuic (v5)](https://github.com/daeuniverse/dae/discussions/182)
|
- [x] [Tuic (v5)](https://github.com/daeuniverse/dae/discussions/182)
|
||||||
|
- [x] [Juicity](https://github.com/juicity/juicity)
|
||||||
- [x] [Proxy chain (flexible protocol)](https://github.com/daeuniverse/dae/discussions/236)
|
- [x] [Proxy chain (flexible protocol)](https://github.com/daeuniverse/dae/discussions/236)
|
||||||
|
|
||||||
For other requirements, one way to expand protocol support is by using external proxy programs. Below is an example of using the external naiveproxy.
|
For other requirements, one way to expand protocol support is by using external proxy programs. Below is an example of using the external naiveproxy.
|
||||||
|
@ -22,6 +22,9 @@
|
|||||||
- [x] Trojan-gfw
|
- [x] Trojan-gfw
|
||||||
- [x] Trojan-go
|
- [x] Trojan-go
|
||||||
- [x] Tuic (v5)
|
- [x] Tuic (v5)
|
||||||
|
- [x] [Tuic (v5)](https://github.com/daeuniverse/dae/discussions/182)
|
||||||
|
- [x] [Juicity](https://github.com/juicity/juicity)
|
||||||
|
- [x] [Proxy chain (flexible protocol)](https://github.com/daeuniverse/dae/discussions/236)
|
||||||
|
|
||||||
有其他需求的,一种方式是通过外接其他代理程序来扩展协议支持。下面给出外接 naiveproxy 的例子。
|
有其他需求的,一种方式是通过外接其他代理程序来扩展协议支持。下面给出外接 naiveproxy 的例子。
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ subscription {
|
|||||||
# Nodes defined here will be merged as a part of the global node pool.
|
# Nodes defined here will be merged as a part of the global node pool.
|
||||||
node {
|
node {
|
||||||
# Add your node links here.
|
# Add your node links here.
|
||||||
# Support socks5, http, https, ss, ssr, vmess, vless, trojan, tuic, etc.
|
# Support socks5, http, https, ss, ssr, vmess, vless, trojan, tuic, juicity, etc.
|
||||||
# Full support list: https://github.com/daeuniverse/dae/blob/main/docs/en/proxy-protocols.md
|
# Full support list: https://github.com/daeuniverse/dae/blob/main/docs/en/proxy-protocols.md
|
||||||
'socks5://localhost:1080'
|
'socks5://localhost:1080'
|
||||||
mylink: 'ss://LINK'
|
mylink: 'ss://LINK'
|
||||||
|
2
go.mod
2
go.mod
@ -12,7 +12,7 @@ require (
|
|||||||
github.com/json-iterator/go v1.1.12
|
github.com/json-iterator/go v1.1.12
|
||||||
github.com/miekg/dns v1.1.55
|
github.com/miekg/dns v1.1.55
|
||||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
||||||
github.com/mzz2017/softwind v0.0.0-20230723115304-666ec11098b8
|
github.com/mzz2017/softwind v0.0.0-20230729115435-7bfb07d4e1f6
|
||||||
github.com/okzk/sdnotify v0.0.0-20180710141335-d9becc38acbd
|
github.com/okzk/sdnotify v0.0.0-20180710141335-d9becc38acbd
|
||||||
github.com/safchain/ethtool v0.3.0
|
github.com/safchain/ethtool v0.3.0
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
|
4
go.sum
4
go.sum
@ -91,8 +91,8 @@ github.com/mzz2017/disk-bloom v1.0.1 h1:rEF9MiXd9qMW3ibRpqcerLXULoTgRlM21yqqJl1B
|
|||||||
github.com/mzz2017/disk-bloom v1.0.1/go.mod h1:JLHETtUu44Z6iBmsqzkOtFlRvXSlKnxjwiBRDapizDI=
|
github.com/mzz2017/disk-bloom v1.0.1/go.mod h1:JLHETtUu44Z6iBmsqzkOtFlRvXSlKnxjwiBRDapizDI=
|
||||||
github.com/mzz2017/quic-go v0.0.0-20230706143320-cc858d4932b7 h1:9zmZilN02x3byMB2X3x+B4iyKHkucv70WA4hsyZkjo8=
|
github.com/mzz2017/quic-go v0.0.0-20230706143320-cc858d4932b7 h1:9zmZilN02x3byMB2X3x+B4iyKHkucv70WA4hsyZkjo8=
|
||||||
github.com/mzz2017/quic-go v0.0.0-20230706143320-cc858d4932b7/go.mod h1:3H6d55CEofIWWr3gQThiB27+hA3WG5tATtPovzEYPAA=
|
github.com/mzz2017/quic-go v0.0.0-20230706143320-cc858d4932b7/go.mod h1:3H6d55CEofIWWr3gQThiB27+hA3WG5tATtPovzEYPAA=
|
||||||
github.com/mzz2017/softwind v0.0.0-20230723115304-666ec11098b8 h1:T/VA4g5qkPeZFvZ+gkx4SK9wijDSOgFwumEZAxdHZ8U=
|
github.com/mzz2017/softwind v0.0.0-20230729115435-7bfb07d4e1f6 h1:9xuiuwjy5nMtWBUmcGDnGhEzobUnLEG+0T2A4RRnCPE=
|
||||||
github.com/mzz2017/softwind v0.0.0-20230723115304-666ec11098b8/go.mod h1:Fz8fgR7/dbnfR6RLpeOMkUDyebq4xShdmjj+cE5jnJ4=
|
github.com/mzz2017/softwind v0.0.0-20230729115435-7bfb07d4e1f6/go.mod h1:Fz8fgR7/dbnfR6RLpeOMkUDyebq4xShdmjj+cE5jnJ4=
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
|
Reference in New Issue
Block a user