From 36ea09eff4279bf8d1955cd7f4a42c16c975af38 Mon Sep 17 00:00:00 2001 From: snakem982 Date: Fri, 19 Jan 2024 21:20:11 +0800 Subject: [PATCH 01/12] fix: Converter SIP002 parameters parse (#976) --- common/convert/converter.go | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/common/convert/converter.go b/common/convert/converter.go index bf5bcbd7..809aa94f 100644 --- a/common/convert/converter.go +++ b/common/convert/converter.go @@ -68,7 +68,8 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { hysteria["skip-cert-verify"], _ = strconv.ParseBool(query.Get("insecure")) proxies = append(proxies, hysteria) - case "hysteria2": + + case "hysteria2", "hy2": urlHysteria2, err := url.Parse(line) if err != nil { continue @@ -79,7 +80,7 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { hysteria2 := make(map[string]any, 20) hysteria2["name"] = name - hysteria2["type"] = scheme + hysteria2["type"] = "hysteria2" hysteria2["server"] = urlHysteria2.Hostname() if port := urlHysteria2.Port(); port != "" { hysteria2["port"] = port @@ -101,6 +102,7 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { hysteria2["up"] = query.Get("up") proxies = append(proxies, hysteria2) + case "tuic": // A temporary unofficial TUIC share link standard // Modified from https://github.com/daeuniverse/dae/discussions/182 @@ -143,7 +145,7 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { } proxies = append(proxies, tuic) - + case "trojan": urlTrojan, err := url.Parse(line) if err != nil { @@ -405,14 +407,27 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { if query.Get("udp-over-tcp") == "true" || query.Get("uot") == "1" { ss["udp-over-tcp"] = true } - if strings.Contains(query.Get("plugin"), "obfs") { - obfsParams := strings.Split(query.Get("plugin"), ";") - ss["plugin"] = "obfs" - ss["plugin-opts"] = map[string]any{ - "host": obfsParams[2][10:], - "mode": obfsParams[1][5:], + plugin := query.Get("plugin") + if strings.Contains(plugin, ";") { + pluginInfo, _ := url.ParseQuery("pluginName=" + strings.ReplaceAll(plugin, ";", "&")) + pluginName := pluginInfo.Get("pluginName") + if strings.Contains(pluginName, "obfs") { + ss["plugin"] = "obfs" + ss["plugin-opts"] = map[string]any{ + "mode": pluginInfo.Get("obfs"), + "host": pluginInfo.Get("obfs-host"), + } + } else if strings.Contains(pluginName, "v2ray-plugin") { + ss["plugin"] = "v2ray-plugin" + ss["plugin-opts"] = map[string]any{ + "mode": pluginInfo.Get("mode"), + "host": pluginInfo.Get("host"), + "path": pluginInfo.Get("path"), + "tls": strings.Contains(plugin, "tls"), + } } } + proxies = append(proxies, ss) case "ssr": From 90ea6ab278894ae6e888ebef3dc3b50b5341a4bb Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 20 Jan 2024 09:48:20 +0800 Subject: [PATCH 02/12] chore: update quic-go to 0.41.0 --- go.mod | 4 ++-- go.sum | 8 ++++---- transport/hysteria/core/client.go | 5 +++-- transport/tuic/v4/packet.go | 2 +- transport/tuic/v5/packet.go | 6 +++--- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index f8252128..82f3ed07 100644 --- a/go.mod +++ b/go.mod @@ -20,8 +20,8 @@ require ( github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 - github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394 - github.com/metacubex/sing-quic v0.0.0-20231220152840-85620b446796 + github.com/metacubex/quic-go v0.41.1-0.20240120014142-a02f4a533d4a + github.com/metacubex/sing-quic v0.0.0-20240120014430-9838ce4bbc41 github.com/metacubex/sing-shadowsocks v0.2.6 github.com/metacubex/sing-shadowsocks2 v0.2.0 github.com/metacubex/sing-tun v0.2.0 diff --git a/go.sum b/go.sum index c3209df8..7137932e 100644 --- a/go.sum +++ b/go.sum @@ -106,12 +106,12 @@ github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvO github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20231209122014-3e43224c7bbc h1:+yTZ6q2EeQCAJNpKNEu5j32Pm23ShD38ElIa635wTrk= github.com/metacubex/gvisor v0.0.0-20231209122014-3e43224c7bbc/go.mod h1:rhBU9tD5ktoGPBtXUquhWuGJ4u+8ZZzBMi2cAdv9q8Y= -github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394 h1:dIT+KB2hknBCrwVAXPeY9tpzzkOZP5m40yqUteRT6/Y= -github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394/go.mod h1:F/t8VnA47xoia8ABlNA4InkZjssvFJ5p6E6jKdbkgAs= +github.com/metacubex/quic-go v0.41.1-0.20240120014142-a02f4a533d4a h1:IMr75VdMnDUhkANZemUWqmOPLfwnemiIaCHRnGCdAsY= +github.com/metacubex/quic-go v0.41.1-0.20240120014142-a02f4a533d4a/go.mod h1:F/t8VnA47xoia8ABlNA4InkZjssvFJ5p6E6jKdbkgAs= github.com/metacubex/sing v0.0.0-20240111014253-f1818b6a82b2 h1:upEO8dt9WDBavhgcgkXB3hRcwVNbkTbnd+xyzy6ZQZo= github.com/metacubex/sing v0.0.0-20240111014253-f1818b6a82b2/go.mod h1:9pfuAH6mZfgnz/YjP6xu5sxx882rfyjpcrTdUpd6w3g= -github.com/metacubex/sing-quic v0.0.0-20231220152840-85620b446796 h1:xiCPttMGAaIh4Ad6t85VxUoUv+Sg88eXzzUvYN8gT5w= -github.com/metacubex/sing-quic v0.0.0-20231220152840-85620b446796/go.mod h1:E1e1Uu6YaJddD+c0DtJlSOkfMI0NLdOVhM60KAlcssY= +github.com/metacubex/sing-quic v0.0.0-20240120014430-9838ce4bbc41 h1:nBo+cgprEu5f6vfJ2lpNvoUh13QUWR3oq1Bul9iF9HY= +github.com/metacubex/sing-quic v0.0.0-20240120014430-9838ce4bbc41/go.mod h1:bdHqEysJclB9BzIa5jcKKSZ1qua+YEPjR8fOzzE3vZU= github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwVSgtE9R3QeFQ= github.com/metacubex/sing-shadowsocks v0.2.6/go.mod h1:zIkMeSnb8Mbf4hdqhw0pjzkn1d99YJ3JQm/VBg5WMTg= github.com/metacubex/sing-shadowsocks2 v0.2.0 h1:hqwT/AfI5d5UdPefIzR6onGHJfDXs5zgOM5QSgaM/9A= diff --git a/transport/hysteria/core/client.go b/transport/hysteria/core/client.go index 258a0005..199fe0d4 100644 --- a/transport/hysteria/core/client.go +++ b/transport/hysteria/core/client.go @@ -402,10 +402,11 @@ func (c *quicPktConn) WriteTo(p []byte, addr string) error { _ = struc.Pack(&msgBuf, &msg) err = c.Session.SendDatagram(msgBuf.Bytes()) if err != nil { - if errSize, ok := err.(quic.ErrMessageTooLarge); ok { + var errSize *quic.DatagramTooLargeError + if errors.As(err, &errSize) { // need to frag msg.MsgID = uint16(fastrand.Intn(0xFFFF)) + 1 // msgID must be > 0 when fragCount > 1 - fragMsgs := fragUDPMessage(msg, int(errSize)) + fragMsgs := fragUDPMessage(msg, int(errSize.PeerMaxDatagramFrameSize)) for _, fragMsg := range fragMsgs { msgBuf.Reset() _ = struc.Pack(&msgBuf, &fragMsg) diff --git a/transport/tuic/v4/packet.go b/transport/tuic/v4/packet.go index f282b3ed..8f5bb5b3 100644 --- a/transport/tuic/v4/packet.go +++ b/transport/tuic/v4/packet.go @@ -123,7 +123,7 @@ func (q *quicStreamPacketConn) WaitReadFrom() (data []byte, put func(), addr net func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { if q.udpRelayMode != common.QUIC && len(p) > q.maxUdpRelayPacketSize { - return 0, quic.ErrMessageTooLarge(q.maxUdpRelayPacketSize) + return 0, &quic.DatagramTooLargeError{PeerMaxDatagramFrameSize: int64(q.maxUdpRelayPacketSize)} } if q.closed { return 0, net.ErrClosed diff --git a/transport/tuic/v5/packet.go b/transport/tuic/v5/packet.go index a34e6a58..86f839a5 100644 --- a/transport/tuic/v5/packet.go +++ b/transport/tuic/v5/packet.go @@ -137,7 +137,7 @@ func (q *quicStreamPacketConn) WaitReadFrom() (data []byte, put func(), addr net func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { if len(p) > 0xffff { // uint16 max - return 0, quic.ErrMessageTooLarge(0xffff) + return 0, &quic.DatagramTooLargeError{PeerMaxDatagramFrameSize: 0xffff} } if q.closed { return 0, net.ErrClosed @@ -187,9 +187,9 @@ func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err erro err = q.quicConn.SendDatagram(data) } - var tooLarge quic.ErrMessageTooLarge + var tooLarge *quic.DatagramTooLargeError if errors.As(err, &tooLarge) { - err = fragWriteNative(q.quicConn, packet, buf, int(tooLarge)-PacketOverHead) + err = fragWriteNative(q.quicConn, packet, buf, int(tooLarge.PeerMaxDatagramFrameSize)-PacketOverHead) } if err != nil { return From 25d6ad220d15aaedf6a07720f59845b3d3c725da Mon Sep 17 00:00:00 2001 From: pretze <105348431+pretzel0373@users.noreply.github.com> Date: Sat, 20 Jan 2024 10:19:42 +0800 Subject: [PATCH 03/12] feat: add DSCP rule for Tproxy UDP packets (#996) * feat: add `DSCP` rule for Tproxy UDP packets * fix: fix compatibility issue with non_linux platform * chore: remove redundant lines for DSCP --- adapter/inbound/addition.go | 6 ++++ constant/metadata.go | 1 + constant/rule.go | 3 ++ listener/tproxy/setsockopt_linux.go | 8 +++++ listener/tproxy/udp.go | 3 ++ listener/tproxy/udp_linux.go | 29 +++++++++++++++++- listener/tproxy/udp_other.go | 4 +++ rules/common/dscp.go | 47 +++++++++++++++++++++++++++++ rules/parser.go | 2 ++ 9 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 rules/common/dscp.go diff --git a/adapter/inbound/addition.go b/adapter/inbound/addition.go index a9896c8c..c38c1aa1 100644 --- a/adapter/inbound/addition.go +++ b/adapter/inbound/addition.go @@ -63,3 +63,9 @@ func WithInAddr(addr net.Addr) Addition { } } } + +func WithDSCP(dscp uint8) Addition { + return func(metadata *C.Metadata) { + metadata.DSCP = dscp + } +} diff --git a/constant/metadata.go b/constant/metadata.go index 3c712909..6df6ff43 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -147,6 +147,7 @@ type Metadata struct { SpecialProxy string `json:"specialProxy"` SpecialRules string `json:"specialRules"` RemoteDst string `json:"remoteDestination"` + DSCP uint8 `json:"dscp"` RawSrcAddr net.Addr `json:"-"` RawDstAddr net.Addr `json:"-"` diff --git a/constant/rule.go b/constant/rule.go index 906f3cef..66fc18bb 100644 --- a/constant/rule.go +++ b/constant/rule.go @@ -14,6 +14,7 @@ const ( SrcPort DstPort InPort + DSCP InUser InName InType @@ -73,6 +74,8 @@ func (rt RuleType) String() string { return "RuleSet" case Network: return "Network" + case DSCP: + return "DSCP" case Uid: return "Uid" case SubRules: diff --git a/listener/tproxy/setsockopt_linux.go b/listener/tproxy/setsockopt_linux.go index 06f3e1c3..b83b28a4 100644 --- a/listener/tproxy/setsockopt_linux.go +++ b/listener/tproxy/setsockopt_linux.go @@ -34,6 +34,14 @@ func setsockopt(rc syscall.RawConn, addr string) error { if err == nil && isIPv6 { err = syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, IPV6_RECVORIGDSTADDR, 1) } + + if err == nil { + err = syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_RECVTOS, 1) + } + + if err == nil { + err = syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, syscall.IPV6_RECVTCLASS, 1) + } }) return err diff --git a/listener/tproxy/udp.go b/listener/tproxy/udp.go index aa0fee19..f738ef0d 100644 --- a/listener/tproxy/udp.go +++ b/listener/tproxy/udp.go @@ -79,6 +79,9 @@ func NewUDP(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*UDPLi continue } + dscp, _ := getDSCP(oob[:oobn]) + additions = append(additions, inbound.WithDSCP(dscp)) + if rAddr.Addr().Is4() { // try to unmap 4in6 address lAddr = netip.AddrPortFrom(lAddr.Addr().Unmap(), lAddr.Port()) diff --git a/listener/tproxy/udp_linux.go b/listener/tproxy/udp_linux.go index 472a23d3..02b51379 100644 --- a/listener/tproxy/udp_linux.go +++ b/listener/tproxy/udp_linux.go @@ -104,7 +104,7 @@ func getOrigDst(oob []byte) (netip.AddrPort, error) { } // retrieve the destination address from the SCM. - sa, err := unix.ParseOrigDstAddr(&scms[0]) + sa, err := unix.ParseOrigDstAddr(&scms[1]) if err != nil { return netip.AddrPort{}, fmt.Errorf("retrieve destination: %w", err) } @@ -122,3 +122,30 @@ func getOrigDst(oob []byte) (netip.AddrPort, error) { return rAddr, nil } + +func getDSCP (oob []byte) (uint8, error) { + scms, err := unix.ParseSocketControlMessage(oob) + if err != nil { + return 0, fmt.Errorf("parse control message: %w", err) + } + dscp, err := parseDSCP(&scms[0]) + if err != nil { + return 0, fmt.Errorf("retrieve DSCP: %w", err) + } + return dscp, nil +} + +func parseDSCP(m *unix.SocketControlMessage) (uint8, error) { + switch { + case m.Header.Level == unix.SOL_IP && m.Header.Type == unix.IP_TOS: + dscp := uint8(m.Data[0] >> 2) + return dscp, nil + + case m.Header.Level == unix.SOL_IPV6 && m.Header.Type == unix.IPV6_TCLASS: + dscp := uint8(m.Data[0] >> 2) + return dscp, nil + + default: + return 0, nil + } +} diff --git a/listener/tproxy/udp_other.go b/listener/tproxy/udp_other.go index b35b07dd..2e0e0ae7 100644 --- a/listener/tproxy/udp_other.go +++ b/listener/tproxy/udp_other.go @@ -12,6 +12,10 @@ func getOrigDst(oob []byte) (netip.AddrPort, error) { return netip.AddrPort{}, errors.New("UDP redir not supported on current platform") } +func getDSCP(oob []byte) (uint8, error) { + return 0, errors.New("UDP redir not supported on current platform") +} + func dialUDP(network string, lAddr, rAddr netip.AddrPort) (*net.UDPConn, error) { return nil, errors.New("UDP redir not supported on current platform") } diff --git a/rules/common/dscp.go b/rules/common/dscp.go new file mode 100644 index 00000000..baedb28d --- /dev/null +++ b/rules/common/dscp.go @@ -0,0 +1,47 @@ +package common + +import ( + "fmt" + "strconv" + + C "github.com/metacubex/mihomo/constant" +) + +type DSCP struct { + *Base + dscp uint8 + payload string + adapter string +} + +func (d *DSCP) RuleType() C.RuleType { + return C.DSCP +} + +func (d *DSCP) Match(metadata *C.Metadata) (bool, string) { + return metadata.DSCP == d.dscp, d.adapter +} + +func (d *DSCP) Adapter() string { + return d.adapter +} + +func (d *DSCP) Payload() string { + return d.payload +} + +func NewDSCP(dscp string, adapter string) (*DSCP, error) { + dscpi, err := strconv.Atoi(dscp) + if err != nil { + return nil, fmt.Errorf("parse DSCP rule fail: %w", err) + } + if dscpi < 0 || dscpi > 63 { + return nil, fmt.Errorf("DSCP couldn't be negative or exceed 63") + } + return &DSCP{ + Base: &Base{}, + payload: dscp, + dscp: uint8(dscpi), + adapter: adapter, + }, nil +} diff --git a/rules/parser.go b/rules/parser.go index e2157cef..7a79b18b 100644 --- a/rules/parser.go +++ b/rules/parser.go @@ -38,6 +38,8 @@ func ParseRule(tp, payload, target string, params []string, subRules map[string] parsed, parseErr = RC.NewPort(payload, target, C.DstPort) case "IN-PORT": parsed, parseErr = RC.NewPort(payload, target, C.InPort) + case "DSCP": + parsed, parseErr = RC.NewDSCP(payload, target) case "PROCESS-NAME": parsed, parseErr = RC.NewProcess(payload, target, true) case "PROCESS-PATH": From 0e1bdb07d4e8bc45a0715f8b9a83d70de2b5a093 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 20 Jan 2024 11:00:06 +0800 Subject: [PATCH 04/12] chore: rewrite IntRanges constructor --- adapter/outboundgroup/fallback.go | 2 +- adapter/outboundgroup/parser.go | 2 +- adapter/provider/parser.go | 2 +- common/utils/ranges.go | 42 +++++++++++++++++++++++++++---- config/config.go | 4 +-- hub/route/groups.go | 2 +- hub/route/proxies.go | 2 +- rules/common/port.go | 2 +- rules/common/uid.go | 2 +- 9 files changed, 46 insertions(+), 14 deletions(-) diff --git a/adapter/outboundgroup/fallback.go b/adapter/outboundgroup/fallback.go index 9db97cf3..4c8a2247 100644 --- a/adapter/outboundgroup/fallback.go +++ b/adapter/outboundgroup/fallback.go @@ -141,7 +141,7 @@ func (f *Fallback) Set(name string) error { if !p.AliveForTestUrl(f.testUrl) { ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(5000)) defer cancel() - expectedStatus, _ := utils.NewIntRanges[uint16](f.expectedStatus) + expectedStatus, _ := utils.NewUnsignedRanges[uint16](f.expectedStatus) _, _ = p.URLTest(ctx, f.testUrl, expectedStatus) } diff --git a/adapter/outboundgroup/parser.go b/adapter/outboundgroup/parser.go index de20c6ea..84b7ccd6 100644 --- a/adapter/outboundgroup/parser.go +++ b/adapter/outboundgroup/parser.go @@ -80,7 +80,7 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide return nil, fmt.Errorf("%s: %w", groupName, errMissProxy) } - expectedStatus, err := utils.NewIntRanges[uint16](groupOption.ExpectedStatus) + expectedStatus, err := utils.NewUnsignedRanges[uint16](groupOption.ExpectedStatus) if err != nil { return nil, fmt.Errorf("%s: %w", groupName, err) } diff --git a/adapter/provider/parser.go b/adapter/provider/parser.go index c78a9d39..9956dc8c 100644 --- a/adapter/provider/parser.go +++ b/adapter/provider/parser.go @@ -63,7 +63,7 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide return nil, err } - expectedStatus, err := utils.NewIntRanges[uint16](schema.HealthCheck.ExpectedStatus) + expectedStatus, err := utils.NewUnsignedRanges[uint16](schema.HealthCheck.ExpectedStatus) if err != nil { return nil, err } diff --git a/common/utils/ranges.go b/common/utils/ranges.go index f36c22ec..810105ff 100644 --- a/common/utils/ranges.go +++ b/common/utils/ranges.go @@ -13,7 +13,7 @@ type IntRanges[T constraints.Integer] []Range[T] var errIntRanges = errors.New("intRanges error") -func NewIntRanges[T constraints.Integer](expected string) (IntRanges[T], error) { +func newIntRanges[T constraints.Integer](expected string, parseFn func(string) (T, error)) (IntRanges[T], error) { // example: 200 or 200/302 or 200-400 or 200/204/401-429/501-503 expected = strings.TrimSpace(expected) if len(expected) == 0 || expected == "*" { @@ -25,10 +25,10 @@ func NewIntRanges[T constraints.Integer](expected string) (IntRanges[T], error) return nil, fmt.Errorf("%w, too many ranges to use, maximum support 28 ranges", errIntRanges) } - return NewIntRangesFromList[T](list) + return newIntRangesFromList[T](list, parseFn) } -func NewIntRangesFromList[T constraints.Integer](list []string) (IntRanges[T], error) { +func newIntRangesFromList[T constraints.Integer](list []string, parseFn func(string) (T, error)) (IntRanges[T], error) { var ranges IntRanges[T] for _, s := range list { if s == "" { @@ -41,7 +41,7 @@ func NewIntRangesFromList[T constraints.Integer](list []string) (IntRanges[T], e return nil, errIntRanges } - start, err := strconv.ParseInt(strings.Trim(status[0], "[ ]"), 10, 64) + start, err := parseFn(strings.Trim(status[0], "[ ]")) if err != nil { return nil, errIntRanges } @@ -50,7 +50,7 @@ func NewIntRangesFromList[T constraints.Integer](list []string) (IntRanges[T], e case 1: ranges = append(ranges, NewRange(T(start), T(start))) case 2: - end, err := strconv.ParseUint(strings.Trim(status[1], "[ ]"), 10, 64) + end, err := parseFn(strings.Trim(status[1], "[ ]")) if err != nil { return nil, errIntRanges } @@ -62,6 +62,38 @@ func NewIntRangesFromList[T constraints.Integer](list []string) (IntRanges[T], e return ranges, nil } +func parseUnsigned[T constraints.Unsigned](s string) (T, error) { + if val, err := strconv.ParseUint(s, 10, 64); err == nil { + return T(val), nil + } else { + return 0, err + } +} + +func NewUnsignedRanges[T constraints.Unsigned](expected string) (IntRanges[T], error) { + return newIntRanges(expected, parseUnsigned[T]) +} + +func NewUnsignedRangesFromList[T constraints.Unsigned](list []string) (IntRanges[T], error) { + return newIntRangesFromList(list, parseUnsigned[T]) +} + +func parseSigned[T constraints.Signed](s string) (T, error) { + if val, err := strconv.ParseInt(s, 10, 64); err == nil { + return T(val), nil + } else { + return 0, err + } +} + +func NewSignedRanges[T constraints.Signed](expected string) (IntRanges[T], error) { + return newIntRanges(expected, parseSigned[T]) +} + +func NewSignedRangesFromList[T constraints.Signed](list []string) (IntRanges[T], error) { + return newIntRangesFromList(list, parseSigned[T]) +} + func (ranges IntRanges[T]) Check(status T) bool { if len(ranges) == 0 { return true diff --git a/config/config.go b/config/config.go index bb503b49..dce61f63 100644 --- a/config/config.go +++ b/config/config.go @@ -1473,7 +1473,7 @@ func parseSniffer(snifferRaw RawSniffer) (*Sniffer, error) { if len(snifferRaw.Sniff) != 0 { for sniffType, sniffConfig := range snifferRaw.Sniff { find := false - ports, err := utils.NewIntRangesFromList[uint16](sniffConfig.Ports) + ports, err := utils.NewUnsignedRangesFromList[uint16](sniffConfig.Ports) if err != nil { return nil, err } @@ -1500,7 +1500,7 @@ func parseSniffer(snifferRaw RawSniffer) (*Sniffer, error) { // Deprecated: Use Sniff instead log.Warnln("Deprecated: Use Sniff instead") } - globalPorts, err := utils.NewIntRangesFromList[uint16](snifferRaw.Ports) + globalPorts, err := utils.NewUnsignedRangesFromList[uint16](snifferRaw.Ports) if err != nil { return nil, err } diff --git a/hub/route/groups.go b/hub/route/groups.go index 18aabf74..30dec5f0 100644 --- a/hub/route/groups.go +++ b/hub/route/groups.go @@ -78,7 +78,7 @@ func getGroupDelay(w http.ResponseWriter, r *http.Request) { return } - expectedStatus, err := utils.NewIntRanges[uint16](query.Get("expected")) + expectedStatus, err := utils.NewUnsignedRanges[uint16](query.Get("expected")) if err != nil { render.Status(r, http.StatusBadRequest) render.JSON(w, r, ErrBadRequest) diff --git a/hub/route/proxies.go b/hub/route/proxies.go index 48359749..69c8e446 100644 --- a/hub/route/proxies.go +++ b/hub/route/proxies.go @@ -113,7 +113,7 @@ func getProxyDelay(w http.ResponseWriter, r *http.Request) { return } - expectedStatus, err := utils.NewIntRanges[uint16](query.Get("expected")) + expectedStatus, err := utils.NewUnsignedRanges[uint16](query.Get("expected")) if err != nil { render.Status(r, http.StatusBadRequest) render.JSON(w, r, ErrBadRequest) diff --git a/rules/common/port.go b/rules/common/port.go index ec76cf30..d3f6e1b4 100644 --- a/rules/common/port.go +++ b/rules/common/port.go @@ -39,7 +39,7 @@ func (p *Port) Payload() string { } func NewPort(port string, adapter string, ruleType C.RuleType) (*Port, error) { - portRanges, err := utils.NewIntRanges[uint16](port) + portRanges, err := utils.NewUnsignedRanges[uint16](port) if err != nil { return nil, fmt.Errorf("%w, %w", errPayload, err) } diff --git a/rules/common/uid.go b/rules/common/uid.go index de46c409..c80632b0 100644 --- a/rules/common/uid.go +++ b/rules/common/uid.go @@ -21,7 +21,7 @@ func NewUid(oUid, adapter string) (*Uid, error) { return nil, fmt.Errorf("uid rule not support this platform") } - uidRange, err := utils.NewIntRanges[uint32](oUid) + uidRange, err := utils.NewUnsignedRanges[uint32](oUid) if err != nil { return nil, fmt.Errorf("%w, %w", errPayload, err) } From c1f0ed18ef82ec80cc309e973d98b20304226a29 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 20 Jan 2024 11:00:29 +0800 Subject: [PATCH 05/12] chore: dscp support range too --- rules/common/dscp.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/rules/common/dscp.go b/rules/common/dscp.go index baedb28d..c839b20d 100644 --- a/rules/common/dscp.go +++ b/rules/common/dscp.go @@ -2,14 +2,14 @@ package common import ( "fmt" - "strconv" + "github.com/metacubex/mihomo/common/utils" C "github.com/metacubex/mihomo/constant" ) type DSCP struct { *Base - dscp uint8 + ranges utils.IntRanges[uint8] payload string adapter string } @@ -19,7 +19,7 @@ func (d *DSCP) RuleType() C.RuleType { } func (d *DSCP) Match(metadata *C.Metadata) (bool, string) { - return metadata.DSCP == d.dscp, d.adapter + return d.ranges.Check(metadata.DSCP), d.adapter } func (d *DSCP) Adapter() string { @@ -31,17 +31,19 @@ func (d *DSCP) Payload() string { } func NewDSCP(dscp string, adapter string) (*DSCP, error) { - dscpi, err := strconv.Atoi(dscp) + ranges, err := utils.NewUnsignedRanges[uint8](dscp) if err != nil { return nil, fmt.Errorf("parse DSCP rule fail: %w", err) } - if dscpi < 0 || dscpi > 63 { - return nil, fmt.Errorf("DSCP couldn't be negative or exceed 63") + for _, r := range ranges { + if r.End() > 63 { + return nil, fmt.Errorf("DSCP couldn't be negative or exceed 63") + } } return &DSCP{ Base: &Base{}, payload: dscp, - dscp: uint8(dscpi), + ranges: ranges, adapter: adapter, }, nil } From e86567ead2579cef92b0408b979251f03fdf69f4 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Sat, 20 Jan 2024 19:43:10 +0800 Subject: [PATCH 06/12] chore: limit the default url --- adapter/outboundgroup/parser.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/adapter/outboundgroup/parser.go b/adapter/outboundgroup/parser.go index 84b7ccd6..6f44b8ea 100644 --- a/adapter/outboundgroup/parser.go +++ b/adapter/outboundgroup/parser.go @@ -92,9 +92,11 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide groupOption.ExpectedStatus = status testUrl := groupOption.URL - if groupOption.URL == "" { - groupOption.URL = C.DefaultTestURL - testUrl = groupOption.URL + if groupOption.Type != "select" && groupOption.Type != "relay" { + if groupOption.URL == "" { + groupOption.URL = C.DefaultTestURL + testUrl = groupOption.URL + } } if len(GroupProxies) != 0 { From 7be6751650f275140a6197265c2511f8f6654fe8 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sun, 21 Jan 2024 16:57:21 +0800 Subject: [PATCH 07/12] fix: trigger-cmfa-update --- .github/workflows/trigger-cmfa-update.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/trigger-cmfa-update.yml b/.github/workflows/trigger-cmfa-update.yml index d767657e..d9523a07 100644 --- a/.github/workflows/trigger-cmfa-update.yml +++ b/.github/workflows/trigger-cmfa-update.yml @@ -15,7 +15,7 @@ on: - Alpha jobs: - # Send "core-updated" to MetaCubeX/MihomoForAndroid to trigger update-dependencies + # Send "core-updated" to MetaCubeX/ClashMetaForAndroid to trigger update-dependencies trigger-CMFA-update: runs-on: ubuntu-latest steps: @@ -27,7 +27,7 @@ jobs: - name: Trigger update-dependencies run: | - curl -X POST https://api.github.com/repos/MetaCubeX/MihomoForAndroid/dispatches \ + curl -X POST https://api.github.com/repos/MetaCubeX/ClashMetaForAndroid/dispatches \ -H "Accept: application/vnd.github.everest-preview+json" \ -H "Authorization: token ${{ steps.generate-token.outputs.token }}" \ - -d '{"event_type": "core-updated"}' \ No newline at end of file + -d '{"event_type": "core-updated"}' From 5c1404f78ef5c9c03258d9404913d876805ba75e Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 22 Jan 2024 20:56:28 +0800 Subject: [PATCH 08/12] chore: hysteria2 add `udp-mtu` option default value is `1200-3` to match old version quic-go's capability --- adapter/outbound/hysteria2.go | 8 ++++++++ go.mod | 2 +- go.sum | 4 ++-- listener/config/hysteria2.go | 1 + listener/inbound/hysteria2.go | 2 ++ listener/sing_hysteria2/server.go | 7 +++++++ transport/tuic/v5/frag.go | 4 +++- 7 files changed, 24 insertions(+), 4 deletions(-) diff --git a/adapter/outbound/hysteria2.go b/adapter/outbound/hysteria2.go index ddd5ccea..47272ec8 100644 --- a/adapter/outbound/hysteria2.go +++ b/adapter/outbound/hysteria2.go @@ -50,6 +50,7 @@ type Hysteria2Option struct { CustomCA string `proxy:"ca,omitempty"` CustomCAString string `proxy:"ca-str,omitempty"` CWND int `proxy:"cwnd,omitempty"` + UdpMTU int `proxy:"udp-mtu,omitempty"` } func (h *Hysteria2) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { @@ -117,6 +118,12 @@ func NewHysteria2(option Hysteria2Option) (*Hysteria2, error) { tlsConfig.NextProtos = option.ALPN } + if option.UdpMTU == 0 { + // "1200" from quic-go's MaxDatagramSize + // "-3" from quic-go's DatagramFrame.MaxDataLen + option.UdpMTU = 1200 - 3 + } + singDialer := proxydialer.NewByNameSingDialer(option.DialerProxy, dialer.NewDialer()) clientOptions := hysteria2.ClientOptions{ @@ -130,6 +137,7 @@ func NewHysteria2(option Hysteria2Option) (*Hysteria2, error) { TLSConfig: tlsConfig, UDPDisabled: false, CWND: option.CWND, + UdpMTU: option.UdpMTU, } client, err := hysteria2.NewClient(clientOptions) diff --git a/go.mod b/go.mod index 82f3ed07..a0d5c447 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 github.com/metacubex/quic-go v0.41.1-0.20240120014142-a02f4a533d4a - github.com/metacubex/sing-quic v0.0.0-20240120014430-9838ce4bbc41 + github.com/metacubex/sing-quic v0.0.0-20240122125415-d6eb83bc6ec4 github.com/metacubex/sing-shadowsocks v0.2.6 github.com/metacubex/sing-shadowsocks2 v0.2.0 github.com/metacubex/sing-tun v0.2.0 diff --git a/go.sum b/go.sum index 7137932e..c30bcbd9 100644 --- a/go.sum +++ b/go.sum @@ -110,8 +110,8 @@ github.com/metacubex/quic-go v0.41.1-0.20240120014142-a02f4a533d4a h1:IMr75VdMnD github.com/metacubex/quic-go v0.41.1-0.20240120014142-a02f4a533d4a/go.mod h1:F/t8VnA47xoia8ABlNA4InkZjssvFJ5p6E6jKdbkgAs= github.com/metacubex/sing v0.0.0-20240111014253-f1818b6a82b2 h1:upEO8dt9WDBavhgcgkXB3hRcwVNbkTbnd+xyzy6ZQZo= github.com/metacubex/sing v0.0.0-20240111014253-f1818b6a82b2/go.mod h1:9pfuAH6mZfgnz/YjP6xu5sxx882rfyjpcrTdUpd6w3g= -github.com/metacubex/sing-quic v0.0.0-20240120014430-9838ce4bbc41 h1:nBo+cgprEu5f6vfJ2lpNvoUh13QUWR3oq1Bul9iF9HY= -github.com/metacubex/sing-quic v0.0.0-20240120014430-9838ce4bbc41/go.mod h1:bdHqEysJclB9BzIa5jcKKSZ1qua+YEPjR8fOzzE3vZU= +github.com/metacubex/sing-quic v0.0.0-20240122125415-d6eb83bc6ec4 h1:4EukI/UdbuaXov7VDDZf4vaP0ZmkUu827DOeQqzVysw= +github.com/metacubex/sing-quic v0.0.0-20240122125415-d6eb83bc6ec4/go.mod h1:bdHqEysJclB9BzIa5jcKKSZ1qua+YEPjR8fOzzE3vZU= github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwVSgtE9R3QeFQ= github.com/metacubex/sing-shadowsocks v0.2.6/go.mod h1:zIkMeSnb8Mbf4hdqhw0pjzkn1d99YJ3JQm/VBg5WMTg= github.com/metacubex/sing-shadowsocks2 v0.2.0 h1:hqwT/AfI5d5UdPefIzR6onGHJfDXs5zgOM5QSgaM/9A= diff --git a/listener/config/hysteria2.go b/listener/config/hysteria2.go index 898204c6..3c9df508 100644 --- a/listener/config/hysteria2.go +++ b/listener/config/hysteria2.go @@ -21,6 +21,7 @@ type Hysteria2Server struct { IgnoreClientBandwidth bool `yaml:"ignore-client-bandwidth" json:"ignore-client-bandwidth,omitempty"` Masquerade string `yaml:"masquerade" json:"masquerade,omitempty"` CWND int `yaml:"cwnd" json:"cwnd,omitempty"` + UdpMTU int `yaml:"udp-mtu" json:"udp-mtu,omitempty"` MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"` } diff --git a/listener/inbound/hysteria2.go b/listener/inbound/hysteria2.go index acd5f9a8..31c2c4b8 100644 --- a/listener/inbound/hysteria2.go +++ b/listener/inbound/hysteria2.go @@ -21,6 +21,7 @@ type Hysteria2Option struct { IgnoreClientBandwidth bool `inbound:"ignore-client-bandwidth,omitempty"` Masquerade string `inbound:"masquerade,omitempty"` CWND int `inbound:"cwnd,omitempty"` + UdpMTU int `inbound:"udp-mtu,omitempty"` MuxOption MuxOption `inbound:"mux-option,omitempty"` } @@ -58,6 +59,7 @@ func NewHysteria2(options *Hysteria2Option) (*Hysteria2, error) { IgnoreClientBandwidth: options.IgnoreClientBandwidth, Masquerade: options.Masquerade, CWND: options.CWND, + UdpMTU: options.UdpMTU, MuxOption: options.MuxOption.Build(), }, }, nil diff --git a/listener/sing_hysteria2/server.go b/listener/sing_hysteria2/server.go index de4c95f5..77ad8efd 100644 --- a/listener/sing_hysteria2/server.go +++ b/listener/sing_hysteria2/server.go @@ -104,6 +104,12 @@ func New(config LC.Hysteria2Server, tunnel C.Tunnel, additions ...inbound.Additi } } + if config.UdpMTU == 0 { + // "1200" from quic-go's MaxDatagramSize + // "-3" from quic-go's DatagramFrame.MaxDataLen + config.UdpMTU = 1200 - 3 + } + service, err := hysteria2.NewService[string](hysteria2.ServiceOptions{ Context: context.Background(), Logger: log.SingLogger, @@ -115,6 +121,7 @@ func New(config LC.Hysteria2Server, tunnel C.Tunnel, additions ...inbound.Additi Handler: h, MasqueradeHandler: masqueradeHandler, CWND: config.CWND, + UdpMTU: config.UdpMTU, }) if err != nil { return nil, err diff --git a/transport/tuic/v5/frag.go b/transport/tuic/v5/frag.go index b0e1a174..d680a5d0 100644 --- a/transport/tuic/v5/frag.go +++ b/transport/tuic/v5/frag.go @@ -12,7 +12,9 @@ import ( // MaxFragSize is a safe udp relay packet size // because tuicv5 support udp fragment so we unneeded to do a magic modify for quic-go to increase MaxDatagramFrameSize // it may not work fine in some platform -var MaxFragSize = 1200 - PacketOverHead +// "1200" from quic-go's MaxDatagramSize +// "-3" from quic-go's DatagramFrame.MaxDataLen +var MaxFragSize = 1200 - PacketOverHead - 3 func fragWriteNative(quicConn quic.Connection, packet Packet, buf *bytes.Buffer, fragSize int) (err error) { fullPayload := packet.DATA From 5858384631c454b03c7a359a6db9819b23ec2a15 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Wed, 24 Jan 2024 11:33:37 +0800 Subject: [PATCH 09/12] chore: modify initial resource update --- component/resource/fetcher.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/component/resource/fetcher.go b/component/resource/fetcher.go index 44ca45c2..e6291293 100644 --- a/component/resource/fetcher.go +++ b/component/resource/fetcher.go @@ -13,10 +13,6 @@ import ( "github.com/samber/lo" ) -const ( - minInterval = time.Minute * 5 -) - var ( fileMode os.FileMode = 0o666 dirMode os.FileMode = 0o755 @@ -164,8 +160,8 @@ func (f *Fetcher[V]) Destroy() error { func (f *Fetcher[V]) pullLoop() { initialInterval := f.interval - time.Since(f.UpdatedAt) - if initialInterval < minInterval { - initialInterval = minInterval + if initialInterval > f.interval { + initialInterval = f.interval } timer := time.NewTimer(initialInterval) From 80d6ca8ef96eb3a00dfb3c712d384016c392ed20 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 24 Jan 2024 11:54:07 +0800 Subject: [PATCH 10/12] fix: h2mux udp not working --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a0d5c447..6f598042 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,7 @@ require ( github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 github.com/sagernet/sing v0.3.0 - github.com/sagernet/sing-mux v0.2.0 + github.com/sagernet/sing-mux v0.2.1-0.20240124034317-9bfb33698bb6 github.com/sagernet/sing-shadowtls v0.1.4 github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6 github.com/sagernet/utls v1.5.4 diff --git a/go.sum b/go.sum index c30bcbd9..bb942b7f 100644 --- a/go.sum +++ b/go.sum @@ -157,8 +157,8 @@ github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkk github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= -github.com/sagernet/sing-mux v0.2.0 h1:4C+vd8HztJCWNYfufvgL49xaOoOHXty2+EAjnzN3IYo= -github.com/sagernet/sing-mux v0.2.0/go.mod h1:khzr9AOPocLa+g53dBplwNDz4gdsyx/YM3swtAhlkHQ= +github.com/sagernet/sing-mux v0.2.1-0.20240124034317-9bfb33698bb6 h1:5bCAkvDDzSMITiHFjolBwpdqYsvycdTu71FsMEFXQ14= +github.com/sagernet/sing-mux v0.2.1-0.20240124034317-9bfb33698bb6/go.mod h1:khzr9AOPocLa+g53dBplwNDz4gdsyx/YM3swtAhlkHQ= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ= From 1025101954133aca16753f020d2b3d0e0ff70d84 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Wed, 24 Jan 2024 12:45:35 +0800 Subject: [PATCH 11/12] chore: add `timeout` option --- adapter/outboundgroup/parser.go | 3 ++- adapter/provider/healthcheck.go | 13 +++++++------ adapter/provider/parser.go | 3 ++- config/config.go | 2 +- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/adapter/outboundgroup/parser.go b/adapter/outboundgroup/parser.go index 6f44b8ea..959041dd 100644 --- a/adapter/outboundgroup/parser.go +++ b/adapter/outboundgroup/parser.go @@ -28,6 +28,7 @@ type GroupCommonOption struct { Use []string `group:"use,omitempty"` URL string `group:"url,omitempty"` Interval int `group:"interval,omitempty"` + TestTimeout int `group:"timeout,omitempty"` Lazy bool `group:"lazy,omitempty"` DisableUDP bool `group:"disable-udp,omitempty"` Filter string `group:"filter,omitempty"` @@ -116,7 +117,7 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide } } - hc := provider.NewHealthCheck(ps, testUrl, uint(groupOption.Interval), groupOption.Lazy, expectedStatus) + hc := provider.NewHealthCheck(ps, testUrl, uint(groupOption.TestTimeout), uint(groupOption.Interval), groupOption.Lazy, expectedStatus) pd, err := provider.NewCompatibleProvider(groupName, ps, hc) if err != nil { diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go index 12e1df42..fbc1d14f 100644 --- a/adapter/provider/healthcheck.go +++ b/adapter/provider/healthcheck.go @@ -16,10 +16,6 @@ import ( "github.com/dlclark/regexp2" ) -const ( - defaultURLTestTimeout = time.Second * 5 -) - type HealthCheckOption struct { URL string Interval uint @@ -42,6 +38,7 @@ type HealthCheck struct { lastTouch atomic.TypedValue[time.Time] done chan struct{} singleDo *singledo.Single[struct{}] + timeout time.Duration } func (hc *HealthCheck) process() { @@ -198,7 +195,7 @@ func (hc *HealthCheck) execute(b *batch.Batch[bool], url, uid string, option *ex p := proxy b.Go(p.Name(), func() (bool, error) { - ctx, cancel := context.WithTimeout(context.Background(), defaultURLTestTimeout) + ctx, cancel := context.WithTimeout(context.Background(), hc.timeout) defer cancel() log.Debugln("Health Checking, proxy: %s, url: %s, id: {%s}", p.Name(), url, uid) _, _ = p.URLTest(ctx, url, expectedStatus) @@ -212,15 +209,19 @@ func (hc *HealthCheck) close() { hc.done <- struct{}{} } -func NewHealthCheck(proxies []C.Proxy, url string, interval uint, lazy bool, expectedStatus utils.IntRanges[uint16]) *HealthCheck { +func NewHealthCheck(proxies []C.Proxy, url string, timeout uint, interval uint, lazy bool, expectedStatus utils.IntRanges[uint16]) *HealthCheck { if url == "" { // expectedStatus = nil url = C.DefaultTestURL } + if timeout == 0 { + timeout = 5000 + } return &HealthCheck{ proxies: proxies, url: url, + timeout: time.Duration(timeout) * time.Millisecond, extra: map[string]*extraOption{}, interval: time.Duration(interval) * time.Second, lazy: lazy, diff --git a/adapter/provider/parser.go b/adapter/provider/parser.go index 9956dc8c..88b36b7c 100644 --- a/adapter/provider/parser.go +++ b/adapter/provider/parser.go @@ -22,6 +22,7 @@ type healthCheckSchema struct { Enable bool `provider:"enable"` URL string `provider:"url"` Interval int `provider:"interval"` + TestTimeout int `provider:"timeout,omitempty"` Lazy bool `provider:"lazy,omitempty"` ExpectedStatus string `provider:"expected-status,omitempty"` } @@ -75,7 +76,7 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide } hcInterval = uint(schema.HealthCheck.Interval) } - hc := NewHealthCheck([]C.Proxy{}, schema.HealthCheck.URL, hcInterval, schema.HealthCheck.Lazy, expectedStatus) + hc := NewHealthCheck([]C.Proxy{}, schema.HealthCheck.URL, uint(schema.HealthCheck.TestTimeout), hcInterval, schema.HealthCheck.Lazy, expectedStatus) var vehicle types.Vehicle switch schema.Type { diff --git a/config/config.go b/config/config.go index dce61f63..b0401596 100644 --- a/config/config.go +++ b/config/config.go @@ -775,7 +775,7 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[ } ps = append(ps, proxies[v]) } - hc := provider.NewHealthCheck(ps, "", 0, true, nil) + hc := provider.NewHealthCheck(ps, "", 5000, 0, true, nil) pd, _ := provider.NewCompatibleProvider(provider.ReservedName, ps, hc) providersMap[provider.ReservedName] = pd From b586b97e382c720288489d86db0635457bff0574 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 24 Jan 2024 13:03:17 +0800 Subject: [PATCH 12/12] fix: fto not working with smux/yamux --- component/dialer/dialer.go | 5 +++++ component/dialer/tfo.go | 7 ++++--- constant/adapters.go | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 985e2195..070d98b8 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -15,6 +15,11 @@ import ( "github.com/metacubex/mihomo/constant/features" ) +const ( + DefaultTCPTimeout = 5 * time.Second + DefaultUDPTimeout = DefaultTCPTimeout +) + type dialFunc func(ctx context.Context, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) var ( diff --git a/component/dialer/tfo.go b/component/dialer/tfo.go index 4863d6ae..6e2f8500 100644 --- a/component/dialer/tfo.go +++ b/component/dialer/tfo.go @@ -2,6 +2,7 @@ package dialer import ( "context" + C "github.com/metacubex/mihomo/constant" "github.com/sagernet/tfo-go" "io" "net" @@ -66,14 +67,14 @@ func (c *tfoConn) Close() error { func (c *tfoConn) LocalAddr() net.Addr { if c.Conn == nil { - return nil + return &net.TCPAddr{} } return c.Conn.LocalAddr() } func (c *tfoConn) RemoteAddr() net.Addr { if c.Conn == nil { - return nil + return &net.TCPAddr{} } return c.Conn.RemoteAddr() } @@ -123,7 +124,7 @@ func (c *tfoConn) WriterReplaceable() bool { } func dialTFO(ctx context.Context, netDialer net.Dialer, network, address string) (net.Conn, error) { - ctx, cancel := context.WithCancel(ctx) + ctx, cancel := context.WithTimeout(context.Background(), DefaultTCPTimeout) dialer := tfo.Dialer{Dialer: netDialer, DisableTFO: false} return &tfoConn{ dialed: make(chan bool, 1), diff --git a/constant/adapters.go b/constant/adapters.go index 9752de55..83c8223a 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -43,9 +43,9 @@ const ( ) const ( - DefaultTCPTimeout = 5 * time.Second + DefaultTCPTimeout = dialer.DefaultTCPTimeout + DefaultUDPTimeout = dialer.DefaultUDPTimeout DefaultDropTime = 12 * DefaultTCPTimeout - DefaultUDPTimeout = DefaultTCPTimeout DefaultTLSTimeout = DefaultTCPTimeout DefaultTestURL = "https://www.gstatic.com/generate_204" )