Skip to content

Commit

Permalink
Merge branch 'apernet:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
cedar2025 authored Nov 19, 2023
2 parents 6f60b3e + 3a77d47 commit 06d255d
Show file tree
Hide file tree
Showing 13 changed files with 186 additions and 55 deletions.
11 changes: 7 additions & 4 deletions app/cmd/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -402,8 +402,8 @@ func runClient(cmd *cobra.Command, args []string) {
logger.Fatal("failed to load client config", zap.Error(err))
}

c, err := client.NewReconnectableClient(hyConfig, func(c client.Client, count int) {
connectLog(count)
c, err := client.NewReconnectableClient(hyConfig, func(c client.Client, info *client.HandshakeInfo, count int) {
connectLog(info, count)
// On the client side, we start checking for updates after we successfully connect
// to the server, which, depending on whether lazy mode is enabled, may or may not
// be immediately after the client starts. We don't want the update check request
Expand Down Expand Up @@ -699,8 +699,11 @@ func (f *adaptiveConnFactory) New(addr net.Addr) (net.PacketConn, error) {
}
}

func connectLog(count int) {
logger.Info("connected to server", zap.Int("count", count))
func connectLog(info *client.HandshakeInfo, count int) {
logger.Info("connected to server",
zap.Bool("udpEnabled", info.UDPEnabled),
zap.Uint64("tx", info.Tx),
zap.Int("count", count))
}

type socks5Logger struct{}
Expand Down
7 changes: 5 additions & 2 deletions app/cmd/ping.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,16 @@ func runPing(cmd *cobra.Command, args []string) {
logger.Fatal("failed to load client config", zap.Error(err))
}

c, err := client.NewClient(hyConfig)
c, info, err := client.NewClient(hyConfig)
if err != nil {
logger.Fatal("failed to initialize client", zap.Error(err))
}
defer c.Close()
logger.Info("connected to server",
zap.Bool("udpEnabled", info.UDPEnabled),
zap.Uint64("tx", info.Tx))

logger.Info("connecting", zap.String("address", addr))
logger.Info("connecting", zap.String("addr", addr))
start := time.Now()
conn, err := c.TCP(addr)
if err != nil {
Expand Down
10 changes: 6 additions & 4 deletions app/cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,11 @@ type serverConfigResolver struct {
}

type serverConfigACL struct {
File string `mapstructure:"file"`
Inline []string `mapstructure:"inline"`
GeoIP string `mapstructure:"geoip"`
GeoSite string `mapstructure:"geosite"`
File string `mapstructure:"file"`
Inline []string `mapstructure:"inline"`
GeoIP string `mapstructure:"geoip"`
GeoSite string `mapstructure:"geosite"`
GeoUpdateInterval time.Duration `mapstructure:"geoUpdateInterval"`
}

type serverConfigOutboundDirect struct {
Expand Down Expand Up @@ -477,6 +478,7 @@ func (c *serverConfig) fillOutboundConfig(hyConfig *server.Config) error {
gLoader := &utils.GeoLoader{
GeoIPFilename: c.ACL.GeoIP,
GeoSiteFilename: c.ACL.GeoSite,
UpdateInterval: c.ACL.GeoUpdateInterval,
DownloadFunc: geoDownloadFunc,
DownloadErrFunc: geoDownloadErrFunc,
}
Expand Down
5 changes: 3 additions & 2 deletions app/cmd/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,9 @@ func TestServerConfig(t *testing.T) {
"lmao(ok)",
"kek(cringe,boba,tea)",
},
GeoIP: "some.dat",
GeoSite: "some_site.dat",
GeoIP: "some.dat",
GeoSite: "some_site.dat",
GeoUpdateInterval: 168 * time.Hour,
},
Outbounds: []serverConfigOutboundEntry{
{
Expand Down
1 change: 1 addition & 0 deletions app/cmd/server_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ acl:
- kek(cringe,boba,tea)
geoip: some.dat
geosite: some_site.dat
geoUpdateInterval: 168h

outbounds:
- name: goodstuff
Expand Down
10 changes: 5 additions & 5 deletions app/internal/utils/bpsconv.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import (
)

const (
Byte = 1.0 << (10 * iota)
Kilobyte
Megabyte
Gigabyte
Terabyte
Byte = 1
Kilobyte = Byte * 1000
Megabyte = Kilobyte * 1000
Gigabyte = Megabyte * 1000
Terabyte = Gigabyte * 1000
)

// StringToBps converts a string to a bandwidth value in bytes per second.
Expand Down
33 changes: 23 additions & 10 deletions app/internal/utils/geoloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"io"
"net/http"
"os"
"time"

"github.com/apernet/hysteria/extras/outbounds/acl"
"github.com/apernet/hysteria/extras/outbounds/acl/v2geo"
Expand All @@ -14,6 +15,8 @@ const (
geoipURL = "https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geoip.dat"
geositeFilename = "geosite.dat"
geositeURL = "https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat"

geoDefaultUpdateInterval = 7 * 24 * time.Hour // 7 days
)

var _ acl.GeoLoader = (*GeoLoader)(nil)
Expand All @@ -24,6 +27,7 @@ var _ acl.GeoLoader = (*GeoLoader)(nil)
type GeoLoader struct {
GeoIPFilename string
GeoSiteFilename string
UpdateInterval time.Duration

DownloadFunc func(filename, url string)
DownloadErrFunc func(err error)
Expand All @@ -32,6 +36,19 @@ type GeoLoader struct {
geositeMap map[string]*v2geo.GeoSite
}

func (l *GeoLoader) shouldDownload(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return true
}
dt := time.Now().Sub(info.ModTime())
if l.UpdateInterval == 0 {
return dt > geoDefaultUpdateInterval
} else {
return dt > l.UpdateInterval
}
}

func (l *GeoLoader) download(filename, url string) error {
l.DownloadFunc(filename, url)

Expand Down Expand Up @@ -64,15 +81,13 @@ func (l *GeoLoader) LoadGeoIP() (map[string]*v2geo.GeoIP, error) {
autoDL = true
filename = geoipFilename
}
m, err := v2geo.LoadGeoIP(filename)
if os.IsNotExist(err) && autoDL {
// It's ok, we will download it.
err = l.download(filename, geoipURL)
if autoDL && l.shouldDownload(filename) {
err := l.download(filename, geoipURL)
if err != nil {
return nil, err
}
m, err = v2geo.LoadGeoIP(filename)
}
m, err := v2geo.LoadGeoIP(filename)
if err != nil {
return nil, err
}
Expand All @@ -90,15 +105,13 @@ func (l *GeoLoader) LoadGeoSite() (map[string]*v2geo.GeoSite, error) {
autoDL = true
filename = geositeFilename
}
m, err := v2geo.LoadGeoSite(filename)
if os.IsNotExist(err) && autoDL {
// It's ok, we will download it.
err = l.download(filename, geositeURL)
if autoDL && l.shouldDownload(filename) {
err := l.download(filename, geositeURL)
if err != nil {
return nil, err
}
m, err = v2geo.LoadGeoSite(filename)
}
m, err := v2geo.LoadGeoSite(filename)
if err != nil {
return nil, err
}
Expand Down
32 changes: 21 additions & 11 deletions core/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,23 @@ type HyUDPConn interface {
Close() error
}

func NewClient(config *Config) (Client, error) {
type HandshakeInfo struct {
UDPEnabled bool
Tx uint64 // 0 if using BBR
}

func NewClient(config *Config) (Client, *HandshakeInfo, error) {
if err := config.verifyAndFill(); err != nil {
return nil, err
return nil, nil, err
}
c := &clientImpl{
config: config,
}
if err := c.connect(); err != nil {
return nil, err
info, err := c.connect()
if err != nil {
return nil, nil, err
}
return c, nil
return c, info, nil
}

type clientImpl struct {
Expand All @@ -56,10 +62,10 @@ type clientImpl struct {
udpSM *udpSessionManager
}

func (c *clientImpl) connect() error {
func (c *clientImpl) connect() (*HandshakeInfo, error) {
pktConn, err := c.config.ConnFactory.New(c.config.ServerAddr)
if err != nil {
return err
return nil, err
}
// Convert config to TLS config & QUIC config
tlsConfig := &tls.Config{
Expand Down Expand Up @@ -113,22 +119,23 @@ func (c *clientImpl) connect() error {
_ = conn.CloseWithError(closeErrCodeProtocolError, "")
}
_ = pktConn.Close()
return coreErrs.ConnectError{Err: err}
return nil, coreErrs.ConnectError{Err: err}
}
if resp.StatusCode != protocol.StatusAuthOK {
_ = conn.CloseWithError(closeErrCodeProtocolError, "")
_ = pktConn.Close()
return coreErrs.AuthError{StatusCode: resp.StatusCode}
return nil, coreErrs.AuthError{StatusCode: resp.StatusCode}
}
// Auth OK
authResp := protocol.AuthResponseFromHeader(resp.Header)
var actualTx uint64
if authResp.RxAuto {
// Server asks client to use bandwidth detection,
// ignore local bandwidth config and use BBR
congestion.UseBBR(conn)
} else {
// actualTx = min(serverRx, clientTx)
actualTx := authResp.Rx
actualTx = authResp.Rx
if actualTx == 0 || actualTx > c.config.BandwidthConfig.MaxTx {
// Server doesn't have a limit, or our clientTx is smaller than serverRx
actualTx = c.config.BandwidthConfig.MaxTx
Expand All @@ -147,7 +154,10 @@ func (c *clientImpl) connect() error {
if authResp.UDPEnabled {
c.udpSM = newUDPSessionManager(&udpIOImpl{Conn: conn})
}
return nil
return &HandshakeInfo{
UDPEnabled: authResp.UDPEnabled,
Tx: actualTx,
}, nil
}

// openStream wraps the stream with QStream, which handles Close() properly
Expand Down
9 changes: 5 additions & 4 deletions core/client/reconnect.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ type reconnectableClientImpl struct {
config *Config
client Client
count int
connectedFunc func(Client, int) // called when successfully connected
connectedFunc func(Client, *HandshakeInfo, int) // called when successfully connected
m sync.Mutex
closed bool // permanent close
}

func NewReconnectableClient(config *Config, connectedFunc func(Client, int), lazy bool) (Client, error) {
func NewReconnectableClient(config *Config, connectedFunc func(Client, *HandshakeInfo, int), lazy bool) (Client, error) {
// Make sure we capture any error in config and return it here,
// so that the caller doesn't have to wait until the first call
// to TCP() or UDP() to get the error (when lazy is true).
Expand All @@ -42,13 +42,14 @@ func (rc *reconnectableClientImpl) reconnect() error {
_ = rc.client.Close()
}
var err error
rc.client, err = NewClient(rc.config)
var info *HandshakeInfo
rc.client, info, err = NewClient(rc.config)
if err != nil {
return err
} else {
rc.count++
if rc.connectedFunc != nil {
rc.connectedFunc(rc, rc.count)
rc.connectedFunc(rc, info, rc.count)
}
return nil
}
Expand Down
8 changes: 4 additions & 4 deletions core/internal/integration_tests/close_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func TestClientServerTCPClose(t *testing.T) {
go s.Serve()

// Create client
c, err := client.NewClient(&client.Config{
c, _, err := client.NewClient(&client.Config{
ServerAddr: udpAddr,
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
})
Expand Down Expand Up @@ -116,7 +116,7 @@ func TestClientServerUDPIdleTimeout(t *testing.T) {
go s.Serve()

// Create client
c, err := client.NewClient(&client.Config{
c, _, err := client.NewClient(&client.Config{
ServerAddr: udpAddr,
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
})
Expand Down Expand Up @@ -194,7 +194,7 @@ func TestClientServerClientShutdown(t *testing.T) {
go s.Serve()

// Create client
c, err := client.NewClient(&client.Config{
c, _, err := client.NewClient(&client.Config{
ServerAddr: udpAddr,
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
})
Expand Down Expand Up @@ -223,7 +223,7 @@ func TestClientServerServerShutdown(t *testing.T) {
go s.Serve()

// Create client
c, err := client.NewClient(&client.Config{
c, _, err := client.NewClient(&client.Config{
ServerAddr: udpAddr,
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
QUICConfig: client.QUICConfig{
Expand Down
Loading

0 comments on commit 06d255d

Please sign in to comment.