Skip to content

Commit

Permalink
fix: hysteria1 outbound should be closed when proxy removed
Browse files Browse the repository at this point in the history
  • Loading branch information
wwqgtxx committed Aug 26, 2024
1 parent 81756fc commit 9cf3eb3
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 5 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ jobs:
if: ${{ matrix.jobs.test == 'test' }}
run: |
go test ./...
echo "---test with_gvisor---"
go test ./... -tags "with_gvisor" -count=1
- name: Update CA
run: |
Expand Down
24 changes: 20 additions & 4 deletions adapter/outbound/hysteria.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import (
"fmt"
"net"
"net/netip"
"runtime"
"strconv"
"time"

"github.com/metacubex/quic-go"
"github.com/metacubex/quic-go/congestion"
M "github.com/sagernet/sing/common/metadata"

CN "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/component/ca"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/proxydialer"
Expand Down Expand Up @@ -43,6 +45,8 @@ type Hysteria struct {

option *HysteriaOption
client *core.Client

closeCh chan struct{} // for test
}

func (h *Hysteria) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
Expand All @@ -51,15 +55,15 @@ func (h *Hysteria) DialContext(ctx context.Context, metadata *C.Metadata, opts .
return nil, err
}

return NewConn(tcpConn, h), nil
return NewConn(CN.NewRefConn(tcpConn, h), h), nil
}

func (h *Hysteria) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
udpConn, err := h.client.DialUDP(h.genHdc(ctx, opts...))
if err != nil {
return nil, err
}
return newPacketConn(&hyPacketConn{udpConn}, h), nil
return newPacketConn(CN.NewRefPacketConn(&hyPacketConn{udpConn}, h), h), nil
}

func (h *Hysteria) genHdc(ctx context.Context, opts ...dialer.Option) utils.PacketDialer {
Expand Down Expand Up @@ -218,7 +222,7 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) {
if err != nil {
return nil, fmt.Errorf("hysteria %s create error: %w", addr, err)
}
return &Hysteria{
outbound := &Hysteria{
Base: &Base{
name: option.Name,
addr: addr,
Expand All @@ -231,7 +235,19 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) {
},
option: &option,
client: client,
}, nil
}
runtime.SetFinalizer(outbound, closeHysteria)

return outbound, nil
}

func closeHysteria(h *Hysteria) {
if h.client != nil {
_ = h.client.Close()
}
if h.closeCh != nil {
close(h.closeCh)
}
}

type hyPacketConn struct {
Expand Down
5 changes: 5 additions & 0 deletions adapter/outbound/hysteria2.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ type Hysteria2 struct {
option *Hysteria2Option
client *hysteria2.Client
dialer proxydialer.SingDialer

closeCh chan struct{} // for test
}

type Hysteria2Option struct {
Expand Down Expand Up @@ -89,6 +91,9 @@ func closeHysteria2(h *Hysteria2) {
if h.client != nil {
_ = h.client.CloseWithError(errors.New("proxy removed"))
}
if h.closeCh != nil {
close(h.closeCh)
}
}

func NewHysteria2(option Hysteria2Option) (*Hysteria2, error) {
Expand Down
38 changes: 38 additions & 0 deletions adapter/outbound/hysteria2_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package outbound

import (
"context"
"runtime"
"testing"
"time"
)

func TestHysteria2GC(t *testing.T) {
option := Hysteria2Option{}
option.Server = "127.0.0.1"
option.Ports = "200,204,401-429,501-503"
option.HopInterval = 30
option.Password = "password"
option.Obfs = "salamander"
option.ObfsPassword = "password"
option.SNI = "example.com"
option.ALPN = []string{"h3"}
hy, err := NewHysteria2(option)
if err != nil {
t.Error(err)
return
}
closeCh := make(chan struct{})
hy.closeCh = closeCh
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()

hy = nil
runtime.GC()
select {
case <-closeCh:
return
case <-ctx.Done():
t.Error("timeout not GC")
}
}
39 changes: 39 additions & 0 deletions adapter/outbound/hysteria_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package outbound

import (
"context"
"runtime"
"testing"
"time"
)

func TestHysteriaGC(t *testing.T) {
option := HysteriaOption{}
option.Server = "127.0.0.1"
option.Ports = "200,204,401-429,501-503"
option.Protocol = "udp"
option.Up = "1Mbps"
option.Down = "1Mbps"
option.HopInterval = 30
option.Obfs = "salamander"
option.SNI = "example.com"
option.ALPN = []string{"h3"}
hy, err := NewHysteria(option)
if err != nil {
t.Error(err)
return
}
closeCh := make(chan struct{})
hy.closeCh = closeCh
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()

hy = nil
runtime.GC()
select {
case <-closeCh:
return
case <-ctx.Done():
t.Error("timeout not GC")
}
}
1 change: 1 addition & 0 deletions adapter/outbound/wireguard_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func TestWireGuardGC(t *testing.T) {
err = wg.init(ctx)
if err != nil {
t.Error(err)
return
}
// must do a small sleep before test GC
// because it maybe deadlocks if w.device.Close call too fast after w.device.Start
Expand Down
5 changes: 4 additions & 1 deletion transport/hysteria/core/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,10 @@ func (c *Client) DialUDP(dialer utils.PacketDialer) (UDPConn, error) {
func (c *Client) Close() error {
c.reconnectMutex.Lock()
defer c.reconnectMutex.Unlock()
err := c.quicSession.CloseWithError(closeErrorCodeGeneric, "")
var err error
if c.quicSession != nil {
err = c.quicSession.CloseWithError(closeErrorCodeGeneric, "")
}
c.closed = true
return err
}
Expand Down

0 comments on commit 9cf3eb3

Please sign in to comment.