Compare commits

...

7 Commits

10 changed files with 67 additions and 40 deletions

View File

@@ -38,6 +38,9 @@ jobs:
if [[ -z "$SOURCE_TAG" ]]; then
SOURCE_TAG="${{ github.ref_name }}"
fi
if [[ -z "$SOURCE_TAG" ]]; then
SOURCE_TAG="${{ github.event.release.tag_name }}"
fi
if [[ -z "$SOURCE_TAG" ]]; then
echo "Error: Could not determine a valid tag source. Input tag and context tag (github.ref_name) are both empty."

View File

@@ -19,7 +19,7 @@ import (
var (
Version_x byte = 25
Version_y byte = 7
Version_z byte = 24
Version_z byte = 25
)
var (

2
go.mod
View File

@@ -20,7 +20,7 @@ require (
github.com/stretchr/testify v1.10.0
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e
github.com/vishvananda/netlink v1.3.1
github.com/xtls/reality v0.0.0-20250723121014-c6320729d93b
github.com/xtls/reality v0.0.0-20250725142056-5b52a03d4fb7
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
golang.org/x/crypto v0.40.0
golang.org/x/net v0.42.0

4
go.sum
View File

@@ -77,8 +77,8 @@ github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW
github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4=
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
github.com/xtls/reality v0.0.0-20250723121014-c6320729d93b h1:HOOsQYu7/EzvpegY7uHiaeI9H/6OsHAOkREnJthdUW8=
github.com/xtls/reality v0.0.0-20250723121014-c6320729d93b/go.mod h1:XxvnCCgBee4WWE0bc4E+a7wbk8gkJ/rS0vNVNtC5qp0=
github.com/xtls/reality v0.0.0-20250725142056-5b52a03d4fb7 h1:Ript0vN+nSO33+Vj4n0mgNY5M+oOxFQJdrJ1VnwTBO0=
github.com/xtls/reality v0.0.0-20250725142056-5b52a03d4fb7/go.mod h1:XxvnCCgBee4WWE0bc4E+a7wbk8gkJ/rS0vNVNtC5qp0=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=

View File

@@ -122,13 +122,19 @@ func executePing(cmd *base.Command, args []string) {
}
func printCertificates(certs []*x509.Certificate) {
var leaf *x509.Certificate
var length int
for _, cert := range certs {
if len(cert.DNSNames) == 0 {
continue
length += len(cert.Raw)
if len(cert.DNSNames) != 0 {
leaf = cert
}
fmt.Println("Cert's signature algorithm: ", cert.SignatureAlgorithm.String())
fmt.Println("Cert's publicKey algorithm: ", cert.PublicKeyAlgorithm.String())
fmt.Println("Cert's allowed domains: ", cert.DNSNames)
}
fmt.Println("Certificate chain's total length: ", length, "(certs count: "+strconv.Itoa(len(certs))+")")
if leaf != nil {
fmt.Println("Cert's signature algorithm: ", leaf.SignatureAlgorithm.String())
fmt.Println("Cert's publicKey algorithm: ", leaf.PublicKeyAlgorithm.String())
fmt.Println("Cert's allowed domains: ", leaf.DNSNames)
}
}

View File

@@ -77,7 +77,8 @@ func (c *UConn) HandshakeAddress() net.Address {
func (c *UConn) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
if c.Config.Show {
localAddr := c.LocalAddr().String()
fmt.Printf("REALITY localAddr: %v\tis using X25519MLKEM768 for TLS' communication: %v\n", localAddr, c.HandshakeState.ServerHello.SelectedGroup == utls.X25519MLKEM768)
curveID := *(*utls.CurveID)(unsafe.Pointer(reflect.ValueOf(c).Elem().FieldByName("curveID").UnsafeAddr()))
fmt.Printf("REALITY localAddr: %v\tis using X25519MLKEM768 for TLS' communication: %v\n", localAddr, curveID == utls.X25519MLKEM768)
fmt.Printf("REALITY localAddr: %v\tis using ML-DSA-65 for cert's extra verification: %v\n", localAddr, len(c.Config.Mldsa65Verify) > 0)
}
p, _ := reflect.TypeOf(c.Conn).Elem().FieldByName("peerCertificates")

View File

@@ -64,26 +64,6 @@ func applyOutboundSocketOptions(network string, address string, fd uintptr, conf
}
}
if config.TcpKeepAliveInterval > 0 || config.TcpKeepAliveIdle > 0 {
if config.TcpKeepAliveInterval > 0 {
if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, int(config.TcpKeepAliveInterval)); err != nil {
return errors.New("failed to set TCP_KEEPINTVL", err)
}
}
if config.TcpKeepAliveIdle > 0 {
if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, int(config.TcpKeepAliveIdle)); err != nil {
return errors.New("failed to set TCP_KEEPIDLE", err)
}
}
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 1); err != nil {
return errors.New("failed to set SO_KEEPALIVE", err)
}
} else if config.TcpKeepAliveInterval < 0 || config.TcpKeepAliveIdle < 0 {
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 0); err != nil {
return errors.New("failed to unset SO_KEEPALIVE", err)
}
}
if config.TcpCongestion != "" {
if err := syscall.SetsockoptString(int(fd), syscall.SOL_TCP, syscall.TCP_CONGESTION, config.TcpCongestion); err != nil {
return errors.New("failed to set TCP_CONGESTION", err)

View File

@@ -3,6 +3,7 @@ package internet
import (
"context"
"math/rand"
gonet "net"
"syscall"
"time"
@@ -87,14 +88,34 @@ func (d *DefaultSystemDialer) Dial(ctx context.Context, src net.Address, dest ne
Dest: destAddr,
}, nil
}
goStdKeepAlive := time.Duration(0)
if sockopt != nil && (sockopt.TcpKeepAliveInterval != 0 || sockopt.TcpKeepAliveIdle != 0) {
goStdKeepAlive = time.Duration(-1)
// Chrome defaults
keepAliveConfig := gonet.KeepAliveConfig{
Enable: true,
Idle: 45 * time.Second,
Interval: 45 * time.Second,
Count: -1,
}
keepAlive := time.Duration(0)
if sockopt != nil {
if sockopt.TcpKeepAliveIdle*sockopt.TcpKeepAliveInterval < 0 {
return nil, errors.New("invalid TcpKeepAliveIdle or TcpKeepAliveInterval value: ", sockopt.TcpKeepAliveIdle, " ", sockopt.TcpKeepAliveInterval)
}
if sockopt.TcpKeepAliveIdle < 0 || sockopt.TcpKeepAliveInterval < 0 {
keepAlive = -1
keepAliveConfig.Enable = false
}
if sockopt.TcpKeepAliveIdle > 0 {
keepAliveConfig.Idle = time.Duration(sockopt.TcpKeepAliveIdle) * time.Second
}
if sockopt.TcpKeepAliveInterval > 0 {
keepAliveConfig.Interval = time.Duration(sockopt.TcpKeepAliveInterval) * time.Second
}
}
dialer := &net.Dialer{
Timeout: time.Second * 16,
LocalAddr: resolveSrcAddr(dest.Network, src),
KeepAlive: goStdKeepAlive,
KeepAlive: keepAlive,
KeepAliveConfig: keepAliveConfig,
}
if sockopt != nil || len(d.controllers) > 0 {

View File

@@ -2,6 +2,7 @@ package internet
import (
"context"
gonet "net"
"os"
"runtime"
"strconv"
@@ -88,9 +89,25 @@ func (dl *DefaultListener) Listen(ctx context.Context, addr net.Addr, sockopt *S
network = addr.Network()
address = addr.String()
lc.Control = getControlFunc(ctx, sockopt, dl.controllers)
// default disable keepalive
lc.KeepAlive = -1
if sockopt != nil {
if sockopt.TcpKeepAliveInterval != 0 || sockopt.TcpKeepAliveIdle != 0 {
lc.KeepAlive = time.Duration(-1)
if sockopt.TcpKeepAliveIdle*sockopt.TcpKeepAliveInterval < 0 {
return nil, errors.New("invalid TcpKeepAliveIdle or TcpKeepAliveInterval value: ", sockopt.TcpKeepAliveIdle, " ", sockopt.TcpKeepAliveInterval)
}
lc.KeepAliveConfig = gonet.KeepAliveConfig{
Enable: false,
Idle: -1,
Interval: -1,
Count: -1,
}
if sockopt.TcpKeepAliveIdle > 0 {
lc.KeepAliveConfig.Enable = true
lc.KeepAliveConfig.Idle = time.Duration(sockopt.TcpKeepAliveIdle) * time.Second
}
if sockopt.TcpKeepAliveInterval > 0 {
lc.KeepAliveConfig.Enable = true
lc.KeepAliveConfig.Interval = time.Duration(sockopt.TcpKeepAliveInterval) * time.Second
}
if sockopt.TcpMptcp {
lc.SetMultipathTCP(true)

View File

@@ -70,11 +70,10 @@ func (v *Dispatcher) getInboundRay(ctx context.Context, dest net.Destination) (*
removeRay := func() {
v.Lock()
defer v.Unlock()
// sometimes the entry is already removed by others, don't close again
if entry == v.conn {
cancel()
v.removeRay()
} else {
errors.LogError(ctx, "removeRay trying to remove a conn that not belongs to it, canceling.")
}
}
timer := signal.CancelAfterInactivity(ctx, removeRay, time.Minute)