mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-08-23 01:56:48 +08:00
Compare commits
25 Commits
remove-wir
...
cfcf2a63d1
Author | SHA1 | Date | |
---|---|---|---|
![]() |
cfcf2a63d1 | ||
![]() |
66025f2889 | ||
![]() |
c9cd26d6d3 | ||
![]() |
caee152adf | ||
![]() |
eb433d9462 | ||
![]() |
87d8b97d9a | ||
![]() |
9d15ecf1f9 | ||
![]() |
4f45c5faa5 | ||
![]() |
26de58933f | ||
![]() |
31b508d372 | ||
![]() |
955a569181 | ||
![]() |
d141d01d0c | ||
![]() |
4e826abebf | ||
![]() |
4433641e30 | ||
![]() |
a196a16c55 | ||
![]() |
8c0bf15901 | ||
![]() |
dbd9125686 | ||
![]() |
923b5d7229 | ||
![]() |
f90fae22aa | ||
![]() |
b065595f58 | ||
![]() |
308f8a7459 | ||
![]() |
050f596e8f | ||
![]() |
3b47d0846e | ||
![]() |
7f23a1cb65 | ||
![]() |
446315cf1f |
3
.github/workflows/docker.yml
vendored
3
.github/workflows/docker.yml
vendored
@@ -38,6 +38,9 @@ jobs:
|
|||||||
if [[ -z "$SOURCE_TAG" ]]; then
|
if [[ -z "$SOURCE_TAG" ]]; then
|
||||||
SOURCE_TAG="${{ github.ref_name }}"
|
SOURCE_TAG="${{ github.ref_name }}"
|
||||||
fi
|
fi
|
||||||
|
if [[ -z "$SOURCE_TAG" ]]; then
|
||||||
|
SOURCE_TAG="${{ github.event.release.tag_name }}"
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ -z "$SOURCE_TAG" ]]; then
|
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."
|
echo "Error: Could not determine a valid tag source. Input tag and context tag (github.ref_name) are both empty."
|
||||||
|
18
README.md
18
README.md
@@ -1,5 +1,9 @@
|
|||||||
# Project X
|
# Project X
|
||||||
|
|
||||||
|
[](https://opensea.io/item/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/1)
|
||||||
|
|
||||||
|
### [Collect a Project X NFT to support the development of Project X!](https://opensea.io/item/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/1)
|
||||||
|
|
||||||
[Project X](https://github.com/XTLS) originates from XTLS protocol, providing a set of network tools such as [Xray-core](https://github.com/XTLS/Xray-core) and [REALITY](https://github.com/XTLS/REALITY).
|
[Project X](https://github.com/XTLS) originates from XTLS protocol, providing a set of network tools such as [Xray-core](https://github.com/XTLS/Xray-core) and [REALITY](https://github.com/XTLS/REALITY).
|
||||||
|
|
||||||
[README](https://github.com/XTLS/Xray-core#readme) is open, so feel free to submit your project [here](https://github.com/XTLS/Xray-core/pulls).
|
[README](https://github.com/XTLS/Xray-core#readme) is open, so feel free to submit your project [here](https://github.com/XTLS/Xray-core/pulls).
|
||||||
@@ -7,8 +11,9 @@
|
|||||||
## Donation & NFTs
|
## Donation & NFTs
|
||||||
|
|
||||||
- **ETH/USDT/USDC: `0xDc3Fe44F0f25D13CACb1C4896CD0D321df3146Ee`**
|
- **ETH/USDT/USDC: `0xDc3Fe44F0f25D13CACb1C4896CD0D321df3146Ee`**
|
||||||
- **Project X NFT: [Announcement of NFTs by Project X](https://github.com/XTLS/Xray-core/discussions/3633)**
|
- **Project X NFT: https://opensea.io/item/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/1**
|
||||||
- **REALITY NFT: [XHTTP: Beyond REALITY](https://github.com/XTLS/Xray-core/discussions/4113)**
|
- **REALITY NFT: https://opensea.io/item/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/2**
|
||||||
|
- **Related links: https://opensea.io/collection/xtls, [Announcement of NFTs by Project X](https://github.com/XTLS/Xray-core/discussions/3633), [XHTTP: Beyond REALITY](https://github.com/XTLS/Xray-core/discussions/4113)**
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
@@ -88,25 +93,28 @@
|
|||||||
- [SaeedDev94/Xray](https://github.com/SaeedDev94/Xray)
|
- [SaeedDev94/Xray](https://github.com/SaeedDev94/Xray)
|
||||||
- [SimpleXray](https://github.com/lhear/SimpleXray)
|
- [SimpleXray](https://github.com/lhear/SimpleXray)
|
||||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||||
- iOS & macOS arm64
|
- iOS & macOS arm64 & tvOS
|
||||||
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215)
|
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215) ([tvOS](https://apps.apple.com/us/app/happ-proxy-utility-for-tv/id6748297274))
|
||||||
- [Streisand](https://apps.apple.com/app/streisand/id6450534064)
|
- [Streisand](https://apps.apple.com/app/streisand/id6450534064)
|
||||||
- [OneXray](https://github.com/OneXray/OneXray)
|
- [OneXray](https://github.com/OneXray/OneXray)
|
||||||
- macOS arm64 & x64
|
- macOS arm64 & x64
|
||||||
|
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215)
|
||||||
- [V2rayU](https://github.com/yanue/V2rayU)
|
- [V2rayU](https://github.com/yanue/V2rayU)
|
||||||
- [V2RayXS](https://github.com/tzmax/V2RayXS)
|
- [V2RayXS](https://github.com/tzmax/V2RayXS)
|
||||||
- [Furious](https://github.com/LorenEteval/Furious)
|
- [Furious](https://github.com/LorenEteval/Furious)
|
||||||
- [OneXray](https://github.com/OneXray/OneXray)
|
- [OneXray](https://github.com/OneXray/OneXray)
|
||||||
|
- [GoXRay](https://github.com/goxray/desktop)
|
||||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||||
- Linux
|
- Linux
|
||||||
- [v2rayA](https://github.com/v2rayA/v2rayA)
|
- [v2rayA](https://github.com/v2rayA/v2rayA)
|
||||||
- [Furious](https://github.com/LorenEteval/Furious)
|
- [Furious](https://github.com/LorenEteval/Furious)
|
||||||
- [GorzRay](https://github.com/ketetefid/GorzRay)
|
- [GorzRay](https://github.com/ketetefid/GorzRay)
|
||||||
|
- [GoXRay](https://github.com/goxray/desktop)
|
||||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||||
|
|
||||||
## Others that support VLESS, XTLS, REALITY, XUDP, PLUX...
|
## Others that support VLESS, XTLS, REALITY, XUDP, PLUX...
|
||||||
|
|
||||||
- iOS & macOS arm64
|
- iOS & macOS arm64 & tvOS
|
||||||
- [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118)
|
- [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118)
|
||||||
- [Loon](https://apps.apple.com/us/app/loon/id1373567447)
|
- [Loon](https://apps.apple.com/us/app/loon/id1373567447)
|
||||||
- Xray Tools
|
- Xray Tools
|
||||||
|
@@ -204,7 +204,12 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, uint32, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Static host lookup
|
// Static host lookup
|
||||||
switch addrs := s.hosts.Lookup(domain, option); {
|
switch addrs, err := s.hosts.Lookup(domain, option); {
|
||||||
|
case err != nil:
|
||||||
|
if go_errors.Is(err, dns.ErrEmptyResponse) {
|
||||||
|
return nil, 0, dns.ErrEmptyResponse
|
||||||
|
}
|
||||||
|
return nil, 0, errors.New("returning nil for domain ", domain).Base(err)
|
||||||
case addrs == nil: // Domain not recorded in static host
|
case addrs == nil: // Domain not recorded in static host
|
||||||
break
|
break
|
||||||
case len(addrs) == 0: // Domain recorded, but no valid IP returned (e.g. IPv4 address with only IPv6 enabled)
|
case len(addrs) == 0: // Domain recorded, but no valid IP returned (e.g. IPv4 address with only IPv6 enabled)
|
||||||
|
@@ -2,6 +2,8 @@ package dns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/strmatcher"
|
"github.com/xtls/xray-core/common/strmatcher"
|
||||||
@@ -31,7 +33,15 @@ func NewStaticHosts(hosts []*Config_HostMapping) (*StaticHosts, error) {
|
|||||||
ips := make([]net.Address, 0, len(mapping.Ip)+1)
|
ips := make([]net.Address, 0, len(mapping.Ip)+1)
|
||||||
switch {
|
switch {
|
||||||
case len(mapping.ProxiedDomain) > 0:
|
case len(mapping.ProxiedDomain) > 0:
|
||||||
ips = append(ips, net.DomainAddress(mapping.ProxiedDomain))
|
if mapping.ProxiedDomain[0] == '#' {
|
||||||
|
rcode, err := strconv.Atoi(mapping.ProxiedDomain[1:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ips = append(ips, dns.RCodeError(rcode))
|
||||||
|
} else {
|
||||||
|
ips = append(ips, net.DomainAddress(mapping.ProxiedDomain))
|
||||||
|
}
|
||||||
case len(mapping.Ip) > 0:
|
case len(mapping.Ip) > 0:
|
||||||
for _, ip := range mapping.Ip {
|
for _, ip := range mapping.Ip {
|
||||||
addr := net.IPAddress(ip)
|
addr := net.IPAddress(ip)
|
||||||
@@ -58,38 +68,51 @@ func filterIP(ips []net.Address, option dns.IPOption) []net.Address {
|
|||||||
return filtered
|
return filtered
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *StaticHosts) lookupInternal(domain string) []net.Address {
|
func (h *StaticHosts) lookupInternal(domain string) ([]net.Address, error) {
|
||||||
ips := make([]net.Address, 0)
|
ips := make([]net.Address, 0)
|
||||||
found := false
|
found := false
|
||||||
for _, id := range h.matchers.Match(domain) {
|
for _, id := range h.matchers.Match(domain) {
|
||||||
|
for _, v := range h.ips[id] {
|
||||||
|
if err, ok := v.(dns.RCodeError); ok {
|
||||||
|
if uint16(err) == 0 {
|
||||||
|
return nil, dns.ErrEmptyResponse
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
ips = append(ips, h.ips[id]...)
|
ips = append(ips, h.ips[id]...)
|
||||||
found = true
|
found = true
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return ips
|
return ips, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *StaticHosts) lookup(domain string, option dns.IPOption, maxDepth int) []net.Address {
|
func (h *StaticHosts) lookup(domain string, option dns.IPOption, maxDepth int) ([]net.Address, error) {
|
||||||
switch addrs := h.lookupInternal(domain); {
|
switch addrs, err := h.lookupInternal(domain); {
|
||||||
|
case err != nil:
|
||||||
|
return nil, err
|
||||||
case len(addrs) == 0: // Not recorded in static hosts, return nil
|
case len(addrs) == 0: // Not recorded in static hosts, return nil
|
||||||
return addrs
|
return addrs, nil
|
||||||
case len(addrs) == 1 && addrs[0].Family().IsDomain(): // Try to unwrap domain
|
case len(addrs) == 1 && addrs[0].Family().IsDomain(): // Try to unwrap domain
|
||||||
errors.LogDebug(context.Background(), "found replaced domain: ", domain, " -> ", addrs[0].Domain(), ". Try to unwrap it")
|
errors.LogDebug(context.Background(), "found replaced domain: ", domain, " -> ", addrs[0].Domain(), ". Try to unwrap it")
|
||||||
if maxDepth > 0 {
|
if maxDepth > 0 {
|
||||||
unwrapped := h.lookup(addrs[0].Domain(), option, maxDepth-1)
|
unwrapped, err := h.lookup(addrs[0].Domain(), option, maxDepth-1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if unwrapped != nil {
|
if unwrapped != nil {
|
||||||
return unwrapped
|
return unwrapped, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return addrs
|
return addrs, nil
|
||||||
default: // IP record found, return a non-nil IP array
|
default: // IP record found, return a non-nil IP array
|
||||||
return filterIP(addrs, option)
|
return filterIP(addrs, option), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lookup returns IP addresses or proxied domain for the given domain, if exists in this StaticHosts.
|
// Lookup returns IP addresses or proxied domain for the given domain, if exists in this StaticHosts.
|
||||||
func (h *StaticHosts) Lookup(domain string, option dns.IPOption) []net.Address {
|
func (h *StaticHosts) Lookup(domain string, option dns.IPOption) ([]net.Address, error) {
|
||||||
return h.lookup(domain, option, 5)
|
return h.lookup(domain, option, 5)
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,11 @@ import (
|
|||||||
|
|
||||||
func TestStaticHosts(t *testing.T) {
|
func TestStaticHosts(t *testing.T) {
|
||||||
pb := []*Config_HostMapping{
|
pb := []*Config_HostMapping{
|
||||||
|
{
|
||||||
|
Type: DomainMatchingType_Subdomain,
|
||||||
|
Domain: "lan",
|
||||||
|
ProxiedDomain: "#3",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Type: DomainMatchingType_Full,
|
Type: DomainMatchingType_Full,
|
||||||
Domain: "example.com",
|
Domain: "example.com",
|
||||||
@@ -54,7 +59,14 @@ func TestStaticHosts(t *testing.T) {
|
|||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
{
|
{
|
||||||
ips := hosts.Lookup("example.com", dns.IPOption{
|
_, err := hosts.Lookup("example.com.lan", dns.IPOption{})
|
||||||
|
if dns.RCodeFromError(err) != 3 {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ips, _ := hosts.Lookup("example.com", dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
})
|
})
|
||||||
@@ -67,7 +79,7 @@ func TestStaticHosts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
domain := hosts.Lookup("proxy.xray.com", dns.IPOption{
|
domain, _ := hosts.Lookup("proxy.xray.com", dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: false,
|
IPv6Enable: false,
|
||||||
})
|
})
|
||||||
@@ -80,7 +92,7 @@ func TestStaticHosts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
domain := hosts.Lookup("proxy2.xray.com", dns.IPOption{
|
domain, _ := hosts.Lookup("proxy2.xray.com", dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: false,
|
IPv6Enable: false,
|
||||||
})
|
})
|
||||||
@@ -93,7 +105,7 @@ func TestStaticHosts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
ips := hosts.Lookup("www.example.cn", dns.IPOption{
|
ips, _ := hosts.Lookup("www.example.cn", dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
})
|
})
|
||||||
@@ -106,7 +118,7 @@ func TestStaticHosts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
ips := hosts.Lookup("baidu.com", dns.IPOption{
|
ips, _ := hosts.Lookup("baidu.com", dns.IPOption{
|
||||||
IPv4Enable: false,
|
IPv4Enable: false,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
})
|
})
|
||||||
|
@@ -161,6 +161,7 @@ type udpConn struct {
|
|||||||
uplink stats.Counter
|
uplink stats.Counter
|
||||||
downlink stats.Counter
|
downlink stats.Counter
|
||||||
inactive bool
|
inactive bool
|
||||||
|
cancel context.CancelFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *udpConn) setInactive() {
|
func (c *udpConn) setInactive() {
|
||||||
@@ -203,6 +204,9 @@ func (c *udpConn) Write(buf []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *udpConn) Close() error {
|
func (c *udpConn) Close() error {
|
||||||
|
if c.cancel != nil {
|
||||||
|
c.cancel()
|
||||||
|
}
|
||||||
common.Must(c.done.Close())
|
common.Must(c.done.Close())
|
||||||
common.Must(common.Close(c.writer))
|
common.Must(common.Close(c.writer))
|
||||||
return nil
|
return nil
|
||||||
@@ -259,6 +263,7 @@ func (w *udpWorker) getConnection(id connID) (*udpConn, bool) {
|
|||||||
defer w.Unlock()
|
defer w.Unlock()
|
||||||
|
|
||||||
if conn, found := w.activeConn[id]; found && !conn.done.Done() {
|
if conn, found := w.activeConn[id]; found && !conn.done.Done() {
|
||||||
|
conn.updateActivity()
|
||||||
return conn, true
|
return conn, true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,7 +311,8 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
|
|||||||
common.Must(w.checker.Start())
|
common.Must(w.checker.Start())
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
ctx := w.ctx
|
ctx, cancel := context.WithCancel(w.ctx)
|
||||||
|
conn.cancel = cancel
|
||||||
sid := session.NewID()
|
sid := session.NewID()
|
||||||
ctx = c.ContextWithID(ctx, sid)
|
ctx = c.ContextWithID(ctx, sid)
|
||||||
|
|
||||||
|
@@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
func (c *Control) FillInRandom() {
|
func (c *Control) FillInRandom() {
|
||||||
randomLength := dice.Roll(64)
|
randomLength := dice.Roll(64)
|
||||||
|
randomLength++
|
||||||
c.Random = make([]byte, randomLength)
|
c.Random = make([]byte, randomLength)
|
||||||
io.ReadFull(rand.Reader, c.Random)
|
io.ReadFull(rand.Reader, c.Random)
|
||||||
}
|
}
|
||||||
|
@@ -170,7 +170,7 @@ func (p *StaticMuxPicker) PickAvailable() (*mux.ClientWorker, error) {
|
|||||||
if w.draining {
|
if w.draining {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if w.client.Closed() {
|
if w.IsFull() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if w.client.ActiveConnections() < minConn {
|
if w.client.ActiveConnections() < minConn {
|
||||||
@@ -211,6 +211,7 @@ type PortalWorker struct {
|
|||||||
writer buf.Writer
|
writer buf.Writer
|
||||||
reader buf.Reader
|
reader buf.Reader
|
||||||
draining bool
|
draining bool
|
||||||
|
counter uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
|
func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
|
||||||
@@ -244,7 +245,7 @@ func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *PortalWorker) heartbeat() error {
|
func (w *PortalWorker) heartbeat() error {
|
||||||
if w.client.Closed() {
|
if w.Closed() {
|
||||||
return errors.New("client worker stopped")
|
return errors.New("client worker stopped")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,16 +261,21 @@ func (w *PortalWorker) heartbeat() error {
|
|||||||
msg.State = Control_DRAIN
|
msg.State = Control_DRAIN
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
|
w.client.GetTimer().Reset(time.Second * 16)
|
||||||
common.Close(w.writer)
|
common.Close(w.writer)
|
||||||
common.Interrupt(w.reader)
|
common.Interrupt(w.reader)
|
||||||
w.writer = nil
|
w.writer = nil
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err := proto.Marshal(msg)
|
w.counter = (w.counter + 1) % 5
|
||||||
common.Must(err)
|
if w.draining || w.counter == 1 {
|
||||||
mb := buf.MergeBytes(nil, b)
|
b, err := proto.Marshal(msg)
|
||||||
return w.writer.WriteMultiBuffer(mb)
|
common.Must(err)
|
||||||
|
mb := buf.MergeBytes(nil, b)
|
||||||
|
return w.writer.WriteMultiBuffer(mb)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *PortalWorker) IsFull() bool {
|
func (w *PortalWorker) IsFull() bool {
|
||||||
|
@@ -173,6 +173,7 @@ type ClientWorker struct {
|
|||||||
sessionManager *SessionManager
|
sessionManager *SessionManager
|
||||||
link transport.Link
|
link transport.Link
|
||||||
done *done.Instance
|
done *done.Instance
|
||||||
|
timer *time.Ticker
|
||||||
strategy ClientStrategy
|
strategy ClientStrategy
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,6 +188,7 @@ func NewClientWorker(stream transport.Link, s ClientStrategy) (*ClientWorker, er
|
|||||||
sessionManager: NewSessionManager(),
|
sessionManager: NewSessionManager(),
|
||||||
link: stream,
|
link: stream,
|
||||||
done: done.New(),
|
done: done.New(),
|
||||||
|
timer: time.NewTicker(time.Second * 16),
|
||||||
strategy: s,
|
strategy: s,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,9 +211,12 @@ func (m *ClientWorker) Closed() bool {
|
|||||||
return m.done.Done()
|
return m.done.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *ClientWorker) GetTimer() *time.Ticker {
|
||||||
|
return m.timer
|
||||||
|
}
|
||||||
|
|
||||||
func (m *ClientWorker) monitor() {
|
func (m *ClientWorker) monitor() {
|
||||||
timer := time.NewTicker(time.Second * 16)
|
defer m.timer.Stop()
|
||||||
defer timer.Stop()
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@@ -220,7 +225,7 @@ func (m *ClientWorker) monitor() {
|
|||||||
common.Close(m.link.Writer)
|
common.Close(m.link.Writer)
|
||||||
common.Interrupt(m.link.Reader)
|
common.Interrupt(m.link.Reader)
|
||||||
return
|
return
|
||||||
case <-timer.C:
|
case <-m.timer.C:
|
||||||
size := m.sessionManager.Size()
|
size := m.sessionManager.Size()
|
||||||
if size == 0 && m.sessionManager.CloseIfNoSession() {
|
if size == 0 && m.sessionManager.CloseIfNoSession() {
|
||||||
common.Must(m.done.Close())
|
common.Must(m.done.Close())
|
||||||
@@ -276,6 +281,8 @@ func (m *ClientWorker) IsClosing() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsFull returns true if this ClientWorker is unable to accept more connections.
|
||||||
|
// it might be because it is closing, or the number of connections has reached the limit.
|
||||||
func (m *ClientWorker) IsFull() bool {
|
func (m *ClientWorker) IsFull() bool {
|
||||||
if m.IsClosing() || m.Closed() {
|
if m.IsClosing() || m.Closed() {
|
||||||
return true
|
return true
|
||||||
@@ -289,12 +296,12 @@ func (m *ClientWorker) IsFull() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *ClientWorker) Dispatch(ctx context.Context, link *transport.Link) bool {
|
func (m *ClientWorker) Dispatch(ctx context.Context, link *transport.Link) bool {
|
||||||
if m.IsFull() || m.Closed() {
|
if m.IsFull() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
sm := m.sessionManager
|
sm := m.sessionManager
|
||||||
s := sm.Allocate()
|
s := sm.Allocate(&m.strategy)
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@@ -201,11 +201,12 @@ func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata,
|
|||||||
transferType: protocol.TransferTypePacket,
|
transferType: protocol.TransferTypePacket,
|
||||||
XUDP: x,
|
XUDP: x,
|
||||||
}
|
}
|
||||||
go handle(ctx, x.Mux, w.link.Writer)
|
|
||||||
x.Status = Active
|
x.Status = Active
|
||||||
if !w.sessionManager.Add(x.Mux) {
|
if !w.sessionManager.Add(x.Mux) {
|
||||||
x.Mux.Close(false)
|
x.Mux.Close(false)
|
||||||
|
return errors.New("failed to add new session")
|
||||||
}
|
}
|
||||||
|
go handle(ctx, x.Mux, w.link.Writer)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,18 +227,23 @@ func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata,
|
|||||||
if meta.Target.Network == net.Network_UDP {
|
if meta.Target.Network == net.Network_UDP {
|
||||||
s.transferType = protocol.TransferTypePacket
|
s.transferType = protocol.TransferTypePacket
|
||||||
}
|
}
|
||||||
w.sessionManager.Add(s)
|
if !w.sessionManager.Add(s) {
|
||||||
|
s.Close(false)
|
||||||
|
return errors.New("failed to add new session")
|
||||||
|
}
|
||||||
go handle(ctx, s, w.link.Writer)
|
go handle(ctx, s, w.link.Writer)
|
||||||
if !meta.Option.Has(OptionData) {
|
if !meta.Option.Has(OptionData) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
rr := s.NewReader(reader, &meta.Target)
|
rr := s.NewReader(reader, &meta.Target)
|
||||||
if err := buf.Copy(rr, s.output); err != nil {
|
err = buf.Copy(rr, s.output)
|
||||||
buf.Copy(rr, buf.Discard)
|
|
||||||
return s.Close(false)
|
if err != nil && buf.IsWriteError(err) {
|
||||||
|
s.Close(false)
|
||||||
|
return buf.Copy(rr, buf.Discard)
|
||||||
}
|
}
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *ServerWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.BufferedReader) error {
|
func (w *ServerWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.BufferedReader) error {
|
||||||
@@ -304,10 +310,11 @@ func (w *ServerWorker) handleFrame(ctx context.Context, reader *buf.BufferedRead
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *ServerWorker) run(ctx context.Context) {
|
func (w *ServerWorker) run(ctx context.Context) {
|
||||||
input := w.link.Reader
|
reader := &buf.BufferedReader{Reader: w.link.Reader}
|
||||||
reader := &buf.BufferedReader{Reader: input}
|
|
||||||
|
|
||||||
defer w.sessionManager.Close()
|
defer w.sessionManager.Close()
|
||||||
|
defer common.Close(w.link.Writer)
|
||||||
|
defer common.Interrupt(w.link.Reader)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@@ -318,7 +325,6 @@ func (w *ServerWorker) run(ctx context.Context) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Cause(err) != io.EOF {
|
if errors.Cause(err) != io.EOF {
|
||||||
errors.LogInfoInner(ctx, err, "unexpected EOF")
|
errors.LogInfoInner(ctx, err, "unexpected EOF")
|
||||||
common.Interrupt(input)
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@@ -50,11 +50,14 @@ func (m *SessionManager) Count() int {
|
|||||||
return int(m.count)
|
return int(m.count)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *SessionManager) Allocate() *Session {
|
func (m *SessionManager) Allocate(Strategy *ClientStrategy) *Session {
|
||||||
m.Lock()
|
m.Lock()
|
||||||
defer m.Unlock()
|
defer m.Unlock()
|
||||||
|
|
||||||
|
MaxConcurrency := int(Strategy.MaxConcurrency)
|
||||||
|
MaxConnection := uint16(Strategy.MaxConnection)
|
||||||
|
|
||||||
if m.closed {
|
if m.closed || (MaxConcurrency > 0 && len(m.sessions) >= MaxConcurrency) || (MaxConnection > 0 && m.count >= MaxConnection) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -9,7 +9,7 @@ import (
|
|||||||
func TestSessionManagerAdd(t *testing.T) {
|
func TestSessionManagerAdd(t *testing.T) {
|
||||||
m := NewSessionManager()
|
m := NewSessionManager()
|
||||||
|
|
||||||
s := m.Allocate()
|
s := m.Allocate(&ClientStrategy{})
|
||||||
if s.ID != 1 {
|
if s.ID != 1 {
|
||||||
t.Error("id: ", s.ID)
|
t.Error("id: ", s.ID)
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@ func TestSessionManagerAdd(t *testing.T) {
|
|||||||
t.Error("size: ", m.Size())
|
t.Error("size: ", m.Size())
|
||||||
}
|
}
|
||||||
|
|
||||||
s = m.Allocate()
|
s = m.Allocate(&ClientStrategy{})
|
||||||
if s.ID != 2 {
|
if s.ID != 2 {
|
||||||
t.Error("id: ", s.ID)
|
t.Error("id: ", s.ID)
|
||||||
}
|
}
|
||||||
@@ -39,7 +39,7 @@ func TestSessionManagerAdd(t *testing.T) {
|
|||||||
|
|
||||||
func TestSessionManagerClose(t *testing.T) {
|
func TestSessionManagerClose(t *testing.T) {
|
||||||
m := NewSessionManager()
|
m := NewSessionManager()
|
||||||
s := m.Allocate()
|
s := m.Allocate(&ClientStrategy{})
|
||||||
|
|
||||||
if m.CloseIfNoSession() {
|
if m.CloseIfNoSession() {
|
||||||
t.Error("able to close")
|
t.Error("able to close")
|
||||||
|
112
common/utils/typed_sync_map.go
Normal file
112
common/utils/typed_sync_map.go
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TypedSyncMap is a wrapper of sync.Map that provides type-safe for keys and values.
|
||||||
|
// No need to use type assertions every time, so you can have more time to enjoy other things like GochiUsa
|
||||||
|
// If sync.Map methods returned nil, it will return the zero value of the type V.
|
||||||
|
type TypedSyncMap[K, V any] struct {
|
||||||
|
syncMap *sync.Map
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTypedSyncMap creates a new TypedSyncMap
|
||||||
|
// K is key type, V is value type
|
||||||
|
// It is recommended to use pointer types for V because sync.Map might return nil
|
||||||
|
// If sync.Map methods really returned nil, it will return the zero value of the type V
|
||||||
|
func NewTypedSyncMap[K any, V any]() *TypedSyncMap[K, V] {
|
||||||
|
return &TypedSyncMap[K, V]{
|
||||||
|
syncMap: &sync.Map{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear deletes all the entries, resulting in an empty Map.
|
||||||
|
func (m *TypedSyncMap[K, V]) Clear() {
|
||||||
|
m.syncMap.Clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompareAndDelete deletes the entry for key if its value is equal to old.
|
||||||
|
// The old value must be of a comparable type.
|
||||||
|
//
|
||||||
|
// If there is no current value for key in the map, CompareAndDelete
|
||||||
|
// returns false (even if the old value is the nil interface value).
|
||||||
|
func (m *TypedSyncMap[K, V]) CompareAndDelete(key K, old V) (deleted bool) {
|
||||||
|
return m.syncMap.CompareAndDelete(key, old)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompareAndSwap swaps the old and new values for key
|
||||||
|
// if the value stored in the map is equal to old.
|
||||||
|
// The old value must be of a comparable type.
|
||||||
|
func (m *TypedSyncMap[K, V]) CompareAndSwap(key K, old V, new V) (swapped bool) {
|
||||||
|
return m.syncMap.CompareAndSwap(key, old, new)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete deletes the value for a key.
|
||||||
|
func (m *TypedSyncMap[K, V]) Delete(key K) {
|
||||||
|
m.syncMap.Delete(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load returns the value stored in the map for a key, or nil if no
|
||||||
|
// value is present.
|
||||||
|
// The ok result indicates whether value was found in the map.
|
||||||
|
func (m *TypedSyncMap[K, V]) Load(key K) (value V, ok bool) {
|
||||||
|
anyValue, ok := m.syncMap.Load(key)
|
||||||
|
// anyValue might be nil
|
||||||
|
if anyValue != nil {
|
||||||
|
value = anyValue.(V)
|
||||||
|
}
|
||||||
|
return value, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadAndDelete deletes the value for a key, returning the previous value if any.
|
||||||
|
// The loaded result reports whether the key was present.
|
||||||
|
func (m *TypedSyncMap[K, V]) LoadAndDelete(key K) (value V, loaded bool) {
|
||||||
|
anyValue, loaded := m.syncMap.LoadAndDelete(key)
|
||||||
|
if anyValue != nil {
|
||||||
|
value = anyValue.(V)
|
||||||
|
}
|
||||||
|
return value, loaded
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadOrStore returns the existing value for the key if present.
|
||||||
|
// Otherwise, it stores and returns the given value.
|
||||||
|
// The loaded result is true if the value was loaded, false if stored.
|
||||||
|
func (m *TypedSyncMap[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) {
|
||||||
|
anyActual, loaded := m.syncMap.LoadOrStore(key, value)
|
||||||
|
if anyActual != nil {
|
||||||
|
actual = anyActual.(V)
|
||||||
|
}
|
||||||
|
return actual, loaded
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range calls f sequentially for each key and value present in the map.
|
||||||
|
// If f returns false, range stops the iteration.
|
||||||
|
//
|
||||||
|
// Range does not necessarily correspond to any consistent snapshot of the Map's
|
||||||
|
// contents: no key will be visited more than once, but if the value for any key
|
||||||
|
// is stored or deleted concurrently (including by f), Range may reflect any
|
||||||
|
// mapping for that key from any point during the Range call. Range does not
|
||||||
|
// block other methods on the receiver; even f itself may call any method on m.
|
||||||
|
//
|
||||||
|
// Range may be O(N) with the number of elements in the map even if f returns
|
||||||
|
// false after a constant number of calls.
|
||||||
|
func (m *TypedSyncMap[K, V]) Range(f func(key K, value V) bool) {
|
||||||
|
m.syncMap.Range(func(key, value any) bool {
|
||||||
|
return f(key.(K), value.(V))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store sets the value for a key.
|
||||||
|
func (m *TypedSyncMap[K, V]) Store(key K, value V) {
|
||||||
|
m.syncMap.Store(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap swaps the value for a key and returns the previous value if any. The loaded result reports whether the key was present.
|
||||||
|
func (m *TypedSyncMap[K, V]) Swap(key K, value V) (previous V, loaded bool) {
|
||||||
|
anyPrevious, loaded := m.syncMap.Swap(key, value)
|
||||||
|
if anyPrevious != nil {
|
||||||
|
previous = anyPrevious.(V)
|
||||||
|
}
|
||||||
|
return previous, loaded
|
||||||
|
}
|
@@ -18,8 +18,8 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
Version_x byte = 25
|
Version_x byte = 25
|
||||||
Version_y byte = 6
|
Version_y byte = 7
|
||||||
Version_z byte = 8
|
Version_z byte = 25
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@@ -42,6 +42,24 @@ func (e RCodeError) Error() string {
|
|||||||
return serial.Concat("rcode: ", uint16(e))
|
return serial.Concat("rcode: ", uint16(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (RCodeError) IP() net.IP {
|
||||||
|
panic("Calling IP() on a RCodeError.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (RCodeError) Domain() string {
|
||||||
|
panic("Calling Domain() on a RCodeError.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (RCodeError) Family() net.AddressFamily {
|
||||||
|
panic("Calling Family() on a RCodeError.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e RCodeError) String() string {
|
||||||
|
return e.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ net.Address = (*RCodeError)(nil)
|
||||||
|
|
||||||
func RCodeFromError(err error) uint16 {
|
func RCodeFromError(err error) uint16 {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return 0
|
return 0
|
||||||
|
17
go.mod
17
go.mod
@@ -13,21 +13,21 @@ require (
|
|||||||
github.com/pelletier/go-toml v1.9.5
|
github.com/pelletier/go-toml v1.9.5
|
||||||
github.com/pires/go-proxyproto v0.8.1
|
github.com/pires/go-proxyproto v0.8.1
|
||||||
github.com/quic-go/quic-go v0.54.0
|
github.com/quic-go/quic-go v0.54.0
|
||||||
github.com/refraction-networking/utls v1.7.3
|
github.com/refraction-networking/utls v1.8.0
|
||||||
github.com/sagernet/sing v0.5.1
|
github.com/sagernet/sing v0.5.1
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.7
|
github.com/sagernet/sing-shadowsocks v0.2.7
|
||||||
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771
|
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771
|
||||||
github.com/stretchr/testify v1.10.0
|
github.com/stretchr/testify v1.10.0
|
||||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e
|
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e
|
||||||
github.com/vishvananda/netlink v1.3.1
|
github.com/vishvananda/netlink v1.3.1
|
||||||
github.com/xtls/reality v0.0.0-20250715055725-05a351a64521
|
github.com/xtls/reality v0.0.0-20250725142056-5b52a03d4fb7
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||||
golang.org/x/crypto v0.40.0
|
golang.org/x/crypto v0.40.0
|
||||||
golang.org/x/net v0.42.0
|
golang.org/x/net v0.42.0
|
||||||
golang.org/x/sync v0.16.0
|
golang.org/x/sync v0.16.0
|
||||||
golang.org/x/sys v0.34.0
|
golang.org/x/sys v0.34.0
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
|
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
|
||||||
google.golang.org/grpc v1.73.0
|
google.golang.org/grpc v1.74.2
|
||||||
google.golang.org/protobuf v1.36.6
|
google.golang.org/protobuf v1.36.6
|
||||||
gvisor.dev/gvisor v0.0.0-20250428193742-2d800c3129d5
|
gvisor.dev/gvisor v0.0.0-20250428193742-2d800c3129d5
|
||||||
h12.io/socks v1.0.3
|
h12.io/socks v1.0.3
|
||||||
@@ -35,13 +35,14 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
github.com/andybalholm/brotli v1.0.6 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
|
github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165 // indirect
|
||||||
github.com/google/btree v1.1.2 // indirect
|
github.com/google/btree v1.1.2 // indirect
|
||||||
github.com/juju/ratelimit v1.0.2 // indirect
|
github.com/juju/ratelimit v1.0.2 // indirect
|
||||||
github.com/klauspost/compress v1.17.8 // indirect
|
github.com/klauspost/compress v1.17.4 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
github.com/klauspost/cpuid/v2 v2.0.12 // indirect
|
||||||
|
github.com/kr/pretty v0.3.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/quic-go/qpack v0.5.1 // indirect
|
github.com/quic-go/qpack v0.5.1 // indirect
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||||
@@ -52,7 +53,7 @@ require (
|
|||||||
golang.org/x/time v0.7.0 // indirect
|
golang.org/x/time v0.7.0 // indirect
|
||||||
golang.org/x/tools v0.34.0 // indirect
|
golang.org/x/tools v0.34.0 // indirect
|
||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
67
go.sum
67
go.sum
@@ -1,19 +1,19 @@
|
|||||||
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0 h1:Wo41lDOevRJSGpevP+8Pk5bANX7fJacO2w04aqLiC5I=
|
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0 h1:Wo41lDOevRJSGpevP+8Pk5bANX7fJacO2w04aqLiC5I=
|
||||||
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0/go.mod h1:FVGavL/QEBQDcBpr3fAojoK17xX5k9bicBphrOpP7uM=
|
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0/go.mod h1:FVGavL/QEBQDcBpr3fAojoK17xX5k9bicBphrOpP7uM=
|
||||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
||||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
||||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165 h1:BS21ZUJ/B5X2UVUbczfmdWH7GapPWAhxcMsDnjJTU1E=
|
||||||
github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
|
github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
|
||||||
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 h1:y7y0Oa6UawqTFPCDw9JG6pdKt4F9pAhHv0B7FMGaGD0=
|
|
||||||
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
|
|
||||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4=
|
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4=
|
||||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
|
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
|
||||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U=
|
github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U=
|
||||||
@@ -32,10 +32,14 @@ github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364 h1:5XxdakFhqd9dnXoA
|
|||||||
github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364/go.mod h1:eDJQioIyy4Yn3MVivT7rv/39gAJTrA7lgmYr8EW950c=
|
github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364/go.mod h1:eDJQioIyy4Yn3MVivT7rv/39gAJTrA7lgmYr8EW950c=
|
||||||
github.com/juju/ratelimit v1.0.2 h1:sRxmtRiajbvrcLQT7S+JbqU0ntsb9W2yhSdNN8tWfaI=
|
github.com/juju/ratelimit v1.0.2 h1:sRxmtRiajbvrcLQT7S+JbqU0ntsb9W2yhSdNN8tWfaI=
|
||||||
github.com/juju/ratelimit v1.0.2/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk=
|
github.com/juju/ratelimit v1.0.2/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk=
|
||||||
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
|
||||||
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/miekg/dns v1.1.67 h1:kg0EHj0G4bfT5/oOys6HhZw4vmMlnoZ+gDu8tJ/AlI0=
|
github.com/miekg/dns v1.1.67 h1:kg0EHj0G4bfT5/oOys6HhZw4vmMlnoZ+gDu8tJ/AlI0=
|
||||||
github.com/miekg/dns v1.1.67/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
|
github.com/miekg/dns v1.1.67/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
|
||||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||||
@@ -44,16 +48,19 @@ github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoU
|
|||||||
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
||||||
github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0=
|
github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0=
|
||||||
github.com/pires/go-proxyproto v0.8.1/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
|
github.com/pires/go-proxyproto v0.8.1/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
|
||||||
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||||
github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg=
|
github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg=
|
||||||
github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
|
github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
|
||||||
github.com/refraction-networking/utls v1.7.3 h1:L0WRhHY7Oq1T0zkdzVZMR6zWZv+sXbHB9zcuvsAEqCo=
|
github.com/refraction-networking/utls v1.8.0 h1:L38krhiTAyj9EeiQQa2sg+hYb4qwLCqdMcpZrRfbONE=
|
||||||
github.com/refraction-networking/utls v1.7.3/go.mod h1:TUhh27RHMGtQvjQq+RyO11P6ZNQNBb3N0v7wsEjKAIQ=
|
github.com/refraction-networking/utls v1.8.0/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y=
|
github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y=
|
||||||
github.com/sagernet/sing v0.5.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
github.com/sagernet/sing v0.5.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
||||||
@@ -70,21 +77,21 @@ 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/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 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
|
||||||
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||||
github.com/xtls/reality v0.0.0-20250715055725-05a351a64521 h1:hQQSzX6Y40nY1XT1TKAEpKwUHUUy3UvYKQIclLjYx9U=
|
github.com/xtls/reality v0.0.0-20250725142056-5b52a03d4fb7 h1:Ript0vN+nSO33+Vj4n0mgNY5M+oOxFQJdrJ1VnwTBO0=
|
||||||
github.com/xtls/reality v0.0.0-20250715055725-05a351a64521/go.mod h1:yD47RN65bDLZgyHWMfFDiqlzrq4usDMt/Xzsk6tMbhw=
|
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=
|
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 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||||
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
|
||||||
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
|
||||||
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
|
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
|
||||||
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
|
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
|
||||||
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
|
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
|
||||||
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
|
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
|
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
|
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
|
||||||
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
|
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
|
||||||
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
|
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
|
||||||
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||||
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
||||||
@@ -111,7 +118,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
@@ -135,14 +141,15 @@ golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeu
|
|||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=
|
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
|
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 h1:e0AIkUUhxyBKh6ssZNrAMeqhA7RKUj42346d1y02i2g=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||||
google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
|
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
|
||||||
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
|
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
|
||||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
@@ -505,16 +505,18 @@ type REALITYConfig struct {
|
|||||||
MaxClientVer string `json:"maxClientVer"`
|
MaxClientVer string `json:"maxClientVer"`
|
||||||
MaxTimeDiff uint64 `json:"maxTimeDiff"`
|
MaxTimeDiff uint64 `json:"maxTimeDiff"`
|
||||||
ShortIds []string `json:"shortIds"`
|
ShortIds []string `json:"shortIds"`
|
||||||
|
Mldsa65Seed string `json:"mldsa65Seed"`
|
||||||
|
|
||||||
LimitFallbackUpload LimitFallback `json:"limitFallbackUpload"`
|
LimitFallbackUpload LimitFallback `json:"limitFallbackUpload"`
|
||||||
LimitFallbackDownload LimitFallback `json:"limitFallbackDownload"`
|
LimitFallbackDownload LimitFallback `json:"limitFallbackDownload"`
|
||||||
|
|
||||||
Fingerprint string `json:"fingerprint"`
|
Fingerprint string `json:"fingerprint"`
|
||||||
ServerName string `json:"serverName"`
|
ServerName string `json:"serverName"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
PublicKey string `json:"publicKey"`
|
PublicKey string `json:"publicKey"`
|
||||||
ShortId string `json:"shortId"`
|
ShortId string `json:"shortId"`
|
||||||
SpiderX string `json:"spiderX"`
|
Mldsa65Verify string `json:"mldsa65Verify"`
|
||||||
|
SpiderX string `json:"spiderX"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *REALITYConfig) Build() (proto.Message, error) {
|
func (c *REALITYConfig) Build() (proto.Message, error) {
|
||||||
@@ -610,6 +612,12 @@ func (c *REALITYConfig) Build() (proto.Message, error) {
|
|||||||
config.ServerNames = c.ServerNames
|
config.ServerNames = c.ServerNames
|
||||||
config.MaxTimeDiff = c.MaxTimeDiff
|
config.MaxTimeDiff = c.MaxTimeDiff
|
||||||
|
|
||||||
|
if c.Mldsa65Seed != "" {
|
||||||
|
if config.Mldsa65Seed, err = base64.RawURLEncoding.DecodeString(c.Mldsa65Seed); err != nil || len(config.Mldsa65Seed) != 32 {
|
||||||
|
return nil, errors.New(`invalid "mldsa65Seed": `, c.Mldsa65Seed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
config.LimitFallbackUpload = new(reality.LimitFallback)
|
config.LimitFallbackUpload = new(reality.LimitFallback)
|
||||||
config.LimitFallbackUpload.AfterBytes = c.LimitFallbackUpload.AfterBytes
|
config.LimitFallbackUpload.AfterBytes = c.LimitFallbackUpload.AfterBytes
|
||||||
config.LimitFallbackUpload.BytesPerSec = c.LimitFallbackUpload.BytesPerSec
|
config.LimitFallbackUpload.BytesPerSec = c.LimitFallbackUpload.BytesPerSec
|
||||||
@@ -645,6 +653,11 @@ func (c *REALITYConfig) Build() (proto.Message, error) {
|
|||||||
if _, err = hex.Decode(config.ShortId, []byte(c.ShortId)); err != nil {
|
if _, err = hex.Decode(config.ShortId, []byte(c.ShortId)); err != nil {
|
||||||
return nil, errors.New(`invalid "shortId": `, c.ShortId)
|
return nil, errors.New(`invalid "shortId": `, c.ShortId)
|
||||||
}
|
}
|
||||||
|
if c.Mldsa65Verify != "" {
|
||||||
|
if config.Mldsa65Verify, err = base64.RawURLEncoding.DecodeString(c.Mldsa65Verify); err != nil || len(config.Mldsa65Verify) != 1952 {
|
||||||
|
return nil, errors.New(`invalid "mldsa65Verify": `, c.Mldsa65Verify)
|
||||||
|
}
|
||||||
|
}
|
||||||
if c.SpiderX == "" {
|
if c.SpiderX == "" {
|
||||||
c.SpiderX = "/"
|
c.SpiderX = "/"
|
||||||
}
|
}
|
||||||
|
@@ -16,5 +16,6 @@ func init() {
|
|||||||
cmdUUID,
|
cmdUUID,
|
||||||
cmdX25519,
|
cmdX25519,
|
||||||
cmdWG,
|
cmdWG,
|
||||||
|
cmdMLDSA65,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
42
main/commands/all/mldsa65.go
Normal file
42
main/commands/all/mldsa65.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package all
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/cloudflare/circl/sign/mldsa/mldsa65"
|
||||||
|
"github.com/xtls/xray-core/main/commands/base"
|
||||||
|
)
|
||||||
|
|
||||||
|
var cmdMLDSA65 = &base.Command{
|
||||||
|
UsageLine: `{{.Exec}} mldsa65 [-i "seed (base64.RawURLEncoding)"]`,
|
||||||
|
Short: `Generate key pair for ML-DSA-65 post-quantum signature`,
|
||||||
|
Long: `
|
||||||
|
Generate key pair for ML-DSA-65 post-quantum signature.
|
||||||
|
|
||||||
|
Random: {{.Exec}} mldsa65
|
||||||
|
|
||||||
|
From seed: {{.Exec}} mldsa65 -i "seed (base64.RawURLEncoding)"
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
cmdMLDSA65.Run = executeMLDSA65 // break init loop
|
||||||
|
}
|
||||||
|
|
||||||
|
var input_seed = cmdMLDSA65.Flag.String("i", "", "")
|
||||||
|
|
||||||
|
func executeMLDSA65(cmd *base.Command, args []string) {
|
||||||
|
var seed [32]byte
|
||||||
|
if len(*input_seed) > 0 {
|
||||||
|
s, _ := base64.RawURLEncoding.DecodeString(*input_seed)
|
||||||
|
seed = [32]byte(s)
|
||||||
|
} else {
|
||||||
|
rand.Read(seed[:])
|
||||||
|
}
|
||||||
|
pub, _ := mldsa65.NewKeyFromSeed(&seed)
|
||||||
|
fmt.Printf("Seed: %v\nVerify: %v",
|
||||||
|
base64.RawURLEncoding.EncodeToString(seed[:]),
|
||||||
|
base64.RawURLEncoding.EncodeToString(pub.Bytes()))
|
||||||
|
}
|
@@ -40,10 +40,12 @@ func executePing(cmd *base.Command, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
domainWithPort := cmdPing.Flag.Arg(0)
|
domainWithPort := cmdPing.Flag.Arg(0)
|
||||||
fmt.Println("Tls ping: ", domainWithPort)
|
fmt.Println("TLS ping: ", domainWithPort)
|
||||||
TargetPort := 443
|
TargetPort := 443
|
||||||
domain, port, err := net.SplitHostPort(domainWithPort)
|
domain, port, err := net.SplitHostPort(domainWithPort)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
|
domain = domainWithPort
|
||||||
|
} else {
|
||||||
TargetPort, _ = strconv.Atoi(port)
|
TargetPort, _ = strconv.Atoi(port)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +63,7 @@ func executePing(cmd *base.Command, args []string) {
|
|||||||
}
|
}
|
||||||
ip = v.IP
|
ip = v.IP
|
||||||
}
|
}
|
||||||
fmt.Println("Using IP: ", ip.String())
|
fmt.Println("Using IP: ", ip.String()+":"+strconv.Itoa(TargetPort))
|
||||||
|
|
||||||
fmt.Println("-------------------")
|
fmt.Println("-------------------")
|
||||||
fmt.Println("Pinging without SNI")
|
fmt.Println("Pinging without SNI")
|
||||||
@@ -72,7 +74,7 @@ func executePing(cmd *base.Command, args []string) {
|
|||||||
}
|
}
|
||||||
tlsConn := gotls.Client(tcpConn, &gotls.Config{
|
tlsConn := gotls.Client(tcpConn, &gotls.Config{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
NextProtos: []string{"http/1.1"},
|
NextProtos: []string{"h2", "http/1.1"},
|
||||||
MaxVersion: gotls.VersionTLS13,
|
MaxVersion: gotls.VersionTLS13,
|
||||||
MinVersion: gotls.VersionTLS12,
|
MinVersion: gotls.VersionTLS12,
|
||||||
// Do not release tool before v5's refactor
|
// Do not release tool before v5's refactor
|
||||||
@@ -98,7 +100,7 @@ func executePing(cmd *base.Command, args []string) {
|
|||||||
}
|
}
|
||||||
tlsConn := gotls.Client(tcpConn, &gotls.Config{
|
tlsConn := gotls.Client(tcpConn, &gotls.Config{
|
||||||
ServerName: domain,
|
ServerName: domain,
|
||||||
NextProtos: []string{"http/1.1"},
|
NextProtos: []string{"h2", "http/1.1"},
|
||||||
MaxVersion: gotls.VersionTLS13,
|
MaxVersion: gotls.VersionTLS13,
|
||||||
MinVersion: gotls.VersionTLS12,
|
MinVersion: gotls.VersionTLS12,
|
||||||
// Do not release tool before v5's refactor
|
// Do not release tool before v5's refactor
|
||||||
@@ -106,24 +108,33 @@ func executePing(cmd *base.Command, args []string) {
|
|||||||
})
|
})
|
||||||
err = tlsConn.Handshake()
|
err = tlsConn.Handshake()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("handshake failure: ", err)
|
fmt.Println("Handshake failure: ", err)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("handshake succeeded")
|
fmt.Println("Handshake succeeded")
|
||||||
printTLSConnDetail(tlsConn)
|
printTLSConnDetail(tlsConn)
|
||||||
printCertificates(tlsConn.ConnectionState().PeerCertificates)
|
printCertificates(tlsConn.ConnectionState().PeerCertificates)
|
||||||
}
|
}
|
||||||
tlsConn.Close()
|
tlsConn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Tls ping finished")
|
fmt.Println("-------------------")
|
||||||
|
fmt.Println("TLS ping finished")
|
||||||
}
|
}
|
||||||
|
|
||||||
func printCertificates(certs []*x509.Certificate) {
|
func printCertificates(certs []*x509.Certificate) {
|
||||||
|
var leaf *x509.Certificate
|
||||||
|
var length int
|
||||||
for _, cert := range certs {
|
for _, cert := range certs {
|
||||||
if len(cert.DNSNames) == 0 {
|
length += len(cert.Raw)
|
||||||
continue
|
if len(cert.DNSNames) != 0 {
|
||||||
|
leaf = cert
|
||||||
}
|
}
|
||||||
fmt.Println("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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,13 +145,13 @@ func printTLSConnDetail(tlsConn *gotls.Conn) {
|
|||||||
} else if tlsConn.ConnectionState().Version == gotls.VersionTLS12 {
|
} else if tlsConn.ConnectionState().Version == gotls.VersionTLS12 {
|
||||||
tlsVersion = "TLS 1.2"
|
tlsVersion = "TLS 1.2"
|
||||||
}
|
}
|
||||||
fmt.Println("TLS Version:", tlsVersion)
|
fmt.Println("TLS Version: ", tlsVersion)
|
||||||
curveID := *(*gotls.CurveID)(unsafe.Pointer(reflect.ValueOf(tlsConn).Elem().FieldByName("curveID").UnsafeAddr()))
|
curveID := *(*gotls.CurveID)(unsafe.Pointer(reflect.ValueOf(tlsConn).Elem().FieldByName("curveID").UnsafeAddr()))
|
||||||
if curveID != 0 {
|
if curveID != 0 {
|
||||||
PostQuantum := (curveID == gotls.X25519MLKEM768)
|
PostQuantum := (curveID == gotls.X25519MLKEM768)
|
||||||
fmt.Println("Post-Quantum key exchange:", PostQuantum, "("+curveID.String()+")")
|
fmt.Println("TLS Post-Quantum key exchange: ", PostQuantum, "("+curveID.String()+")")
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Post-Quantum key exchange: false (RSA Exchange)")
|
fmt.Println("TLS Post-Quantum key exchange: false (RSA Exchange)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -18,6 +18,7 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
"github.com/xtls/xray-core/common/signal"
|
"github.com/xtls/xray-core/common/signal"
|
||||||
"github.com/xtls/xray-core/common/task"
|
"github.com/xtls/xray-core/common/task"
|
||||||
|
"github.com/xtls/xray-core/common/utils"
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
"github.com/xtls/xray-core/features/dns"
|
"github.com/xtls/xray-core/features/dns"
|
||||||
"github.com/xtls/xray-core/features/policy"
|
"github.com/xtls/xray-core/features/policy"
|
||||||
@@ -202,7 +203,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
writer = buf.NewWriter(conn)
|
writer = buf.NewWriter(conn)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
writer = NewPacketWriter(conn, h, ctx, UDPOverride)
|
writer = NewPacketWriter(conn, h, ctx, UDPOverride, destination)
|
||||||
if h.config.Noises != nil {
|
if h.config.Noises != nil {
|
||||||
errors.LogDebug(ctx, "NOISE", h.config.Noises)
|
errors.LogDebug(ctx, "NOISE", h.config.Noises)
|
||||||
writer = &NoisePacketWriter{
|
writer = &NoisePacketWriter{
|
||||||
@@ -238,7 +239,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
if destination.Network == net.Network_TCP {
|
if destination.Network == net.Network_TCP {
|
||||||
reader = buf.NewReader(conn)
|
reader = buf.NewReader(conn)
|
||||||
} else {
|
} else {
|
||||||
reader = NewPacketReader(conn, UDPOverride)
|
reader = NewPacketReader(conn, UDPOverride, destination)
|
||||||
}
|
}
|
||||||
if err := buf.Copy(reader, output, buf.UpdateActivity(timer)); err != nil {
|
if err := buf.Copy(reader, output, buf.UpdateActivity(timer)); err != nil {
|
||||||
return errors.New("failed to process response").Base(err)
|
return errors.New("failed to process response").Base(err)
|
||||||
@@ -273,7 +274,7 @@ func isTLSConn(conn stat.Connection) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPacketReader(conn net.Conn, UDPOverride net.Destination) buf.Reader {
|
func NewPacketReader(conn net.Conn, UDPOverride net.Destination, DialDest net.Destination) buf.Reader {
|
||||||
iConn := conn
|
iConn := conn
|
||||||
statConn, ok := iConn.(*stat.CounterConnection)
|
statConn, ok := iConn.(*stat.CounterConnection)
|
||||||
if ok {
|
if ok {
|
||||||
@@ -283,10 +284,15 @@ func NewPacketReader(conn net.Conn, UDPOverride net.Destination) buf.Reader {
|
|||||||
if statConn != nil {
|
if statConn != nil {
|
||||||
counter = statConn.ReadCounter
|
counter = statConn.ReadCounter
|
||||||
}
|
}
|
||||||
if c, ok := iConn.(*internet.PacketConnWrapper); ok && UDPOverride.Address == nil && UDPOverride.Port == 0 {
|
if c, ok := iConn.(*internet.PacketConnWrapper); ok {
|
||||||
|
isAddrChanged := false
|
||||||
|
if UDPOverride.Address != nil || UDPOverride.Port != 0 || DialDest.Address.Family().IsDomain() {
|
||||||
|
isAddrChanged = true
|
||||||
|
}
|
||||||
return &PacketReader{
|
return &PacketReader{
|
||||||
PacketConnWrapper: c,
|
PacketConnWrapper: c,
|
||||||
Counter: counter,
|
Counter: counter,
|
||||||
|
IsAddrChanged: isAddrChanged,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &buf.PacketReader{Reader: conn}
|
return &buf.PacketReader{Reader: conn}
|
||||||
@@ -295,6 +301,7 @@ func NewPacketReader(conn net.Conn, UDPOverride net.Destination) buf.Reader {
|
|||||||
type PacketReader struct {
|
type PacketReader struct {
|
||||||
*internet.PacketConnWrapper
|
*internet.PacketConnWrapper
|
||||||
stats.Counter
|
stats.Counter
|
||||||
|
IsAddrChanged bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
||||||
@@ -306,10 +313,14 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
b.Resize(0, int32(n))
|
b.Resize(0, int32(n))
|
||||||
b.UDP = &net.Destination{
|
// if udp dest addr is changed, we are unable to get the correct src addr
|
||||||
Address: net.IPAddress(d.(*net.UDPAddr).IP),
|
// so we don't attach src info to udp packet, break cone behavior, assuming the dial dest is the expected scr addr
|
||||||
Port: net.Port(d.(*net.UDPAddr).Port),
|
if !r.IsAddrChanged {
|
||||||
Network: net.Network_UDP,
|
b.UDP = &net.Destination{
|
||||||
|
Address: net.IPAddress(d.(*net.UDPAddr).IP),
|
||||||
|
Port: net.Port(d.(*net.UDPAddr).Port),
|
||||||
|
Network: net.Network_UDP,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if r.Counter != nil {
|
if r.Counter != nil {
|
||||||
r.Counter.Add(int64(n))
|
r.Counter.Add(int64(n))
|
||||||
@@ -317,7 +328,8 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
|||||||
return buf.MultiBuffer{b}, nil
|
return buf.MultiBuffer{b}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPacketWriter(conn net.Conn, h *Handler, ctx context.Context, UDPOverride net.Destination) buf.Writer {
|
// DialDest means the dial target used in the dialer when creating conn
|
||||||
|
func NewPacketWriter(conn net.Conn, h *Handler, ctx context.Context, UDPOverride net.Destination, DialDest net.Destination) buf.Writer {
|
||||||
iConn := conn
|
iConn := conn
|
||||||
statConn, ok := iConn.(*stat.CounterConnection)
|
statConn, ok := iConn.(*stat.CounterConnection)
|
||||||
if ok {
|
if ok {
|
||||||
@@ -328,12 +340,20 @@ func NewPacketWriter(conn net.Conn, h *Handler, ctx context.Context, UDPOverride
|
|||||||
counter = statConn.WriteCounter
|
counter = statConn.WriteCounter
|
||||||
}
|
}
|
||||||
if c, ok := iConn.(*internet.PacketConnWrapper); ok {
|
if c, ok := iConn.(*internet.PacketConnWrapper); ok {
|
||||||
|
// If DialDest is a domain, it will be resolved in dialer
|
||||||
|
// check this behavior and add it to map
|
||||||
|
resolvedUDPAddr := utils.NewTypedSyncMap[string, net.Address]()
|
||||||
|
if DialDest.Address.Family().IsDomain() {
|
||||||
|
RemoteAddress, _, _ := net.SplitHostPort(conn.RemoteAddr().String())
|
||||||
|
resolvedUDPAddr.Store(DialDest.Address.String(), net.ParseAddress(RemoteAddress))
|
||||||
|
}
|
||||||
return &PacketWriter{
|
return &PacketWriter{
|
||||||
PacketConnWrapper: c,
|
PacketConnWrapper: c,
|
||||||
Counter: counter,
|
Counter: counter,
|
||||||
Handler: h,
|
Handler: h,
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
UDPOverride: UDPOverride,
|
UDPOverride: UDPOverride,
|
||||||
|
resolvedUDPAddr: resolvedUDPAddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -346,6 +366,12 @@ type PacketWriter struct {
|
|||||||
*Handler
|
*Handler
|
||||||
context.Context
|
context.Context
|
||||||
UDPOverride net.Destination
|
UDPOverride net.Destination
|
||||||
|
|
||||||
|
// Dest of udp packets might be a domain, we will resolve them to IP
|
||||||
|
// But resolver will return a random one if the domain has many IPs
|
||||||
|
// Resulting in these packets being sent to many different IPs randomly
|
||||||
|
// So, cache and keep the resolve result
|
||||||
|
resolvedUDPAddr *utils.TypedSyncMap[string, net.Address]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||||
@@ -364,10 +390,34 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
|||||||
if w.UDPOverride.Port != 0 {
|
if w.UDPOverride.Port != 0 {
|
||||||
b.UDP.Port = w.UDPOverride.Port
|
b.UDP.Port = w.UDPOverride.Port
|
||||||
}
|
}
|
||||||
if w.Handler.config.hasStrategy() && b.UDP.Address.Family().IsDomain() {
|
if b.UDP.Address.Family().IsDomain() {
|
||||||
ip := w.Handler.resolveIP(w.Context, b.UDP.Address.Domain(), nil)
|
if ip, ok := w.resolvedUDPAddr.Load(b.UDP.Address.Domain()); ok {
|
||||||
if ip != nil {
|
|
||||||
b.UDP.Address = ip
|
b.UDP.Address = ip
|
||||||
|
} else {
|
||||||
|
ShouldUseSystemResolver := true
|
||||||
|
if w.Handler.config.hasStrategy() {
|
||||||
|
ip = w.Handler.resolveIP(w.Context, b.UDP.Address.Domain(), nil)
|
||||||
|
if ip != nil {
|
||||||
|
ShouldUseSystemResolver = false
|
||||||
|
}
|
||||||
|
// drop packet if resolve failed when forceIP
|
||||||
|
if ip == nil && w.Handler.config.forceIP() {
|
||||||
|
b.Release()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ShouldUseSystemResolver {
|
||||||
|
udpAddr, err := net.ResolveUDPAddr("udp", b.UDP.NetAddr())
|
||||||
|
if err != nil {
|
||||||
|
b.Release()
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
ip = net.IPAddress(udpAddr.IP)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ip != nil {
|
||||||
|
b.UDP.Address, _ = w.resolvedUDPAddr.LoadOrStore(b.UDP.Address.Domain(), ip)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
destAddr, _ := net.ResolveUDPAddr("udp", b.UDP.NetAddr())
|
destAddr, _ := net.ResolveUDPAddr("udp", b.UDP.NetAddr())
|
||||||
|
@@ -128,6 +128,7 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn stat.Connection, dis
|
|||||||
|
|
||||||
conn.Write(data.Bytes())
|
conn.Write(data.Bytes())
|
||||||
})
|
})
|
||||||
|
defer udpServer.RemoveRay()
|
||||||
|
|
||||||
inbound := session.InboundFromContext(ctx)
|
inbound := session.InboundFromContext(ctx)
|
||||||
var dest *net.Destination
|
var dest *net.Destination
|
||||||
|
@@ -245,13 +245,15 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn stat.Connection, dis
|
|||||||
udpMessage, err := EncodeUDPPacket(request, payload.Bytes())
|
udpMessage, err := EncodeUDPPacket(request, payload.Bytes())
|
||||||
payload.Release()
|
payload.Release()
|
||||||
|
|
||||||
defer udpMessage.Release()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogWarningInner(ctx, err, "failed to write UDP response")
|
errors.LogWarningInner(ctx, err, "failed to write UDP response")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
defer udpMessage.Release()
|
||||||
|
|
||||||
conn.Write(udpMessage.Bytes())
|
conn.Write(udpMessage.Bytes())
|
||||||
})
|
})
|
||||||
|
defer udpServer.RemoveRay()
|
||||||
|
|
||||||
inbound := session.InboundFromContext(ctx)
|
inbound := session.InboundFromContext(ctx)
|
||||||
if inbound != nil && inbound.Source.IsValid() {
|
if inbound != nil && inbound.Source.IsValid() {
|
||||||
|
@@ -259,6 +259,7 @@ func (s *Server) handleUDPPayload(ctx context.Context, clientReader *PacketReade
|
|||||||
errors.LogWarningInner(ctx, err, "failed to write response")
|
errors.LogWarningInner(ctx, err, "failed to write response")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
defer udpServer.RemoveRay()
|
||||||
|
|
||||||
inbound := session.InboundFromContext(ctx)
|
inbound := session.InboundFromContext(ctx)
|
||||||
user := inbound.User
|
user := inbound.User
|
||||||
|
@@ -206,7 +206,10 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
|
|
||||||
first := buf.FromBytes(make([]byte, buf.Size))
|
first := buf.FromBytes(make([]byte, buf.Size))
|
||||||
first.Clear()
|
first.Clear()
|
||||||
firstLen, _ := first.ReadFrom(connection)
|
firstLen, errR := first.ReadFrom(connection)
|
||||||
|
if errR != nil {
|
||||||
|
return errR
|
||||||
|
}
|
||||||
errors.LogInfo(ctx, "firstLen = ", firstLen)
|
errors.LogInfo(ctx, "firstLen = ", firstLen)
|
||||||
|
|
||||||
reader := &buf.BufferedReader{
|
reader := &buf.BufferedReader{
|
||||||
|
@@ -7,6 +7,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/cloudflare/circl/sign/mldsa/mldsa65"
|
||||||
"github.com/xtls/reality"
|
"github.com/xtls/reality"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
@@ -32,6 +33,10 @@ func (c *Config) GetREALITYConfig() *reality.Config {
|
|||||||
|
|
||||||
KeyLogWriter: KeyLogWriterFromConfig(c),
|
KeyLogWriter: KeyLogWriterFromConfig(c),
|
||||||
}
|
}
|
||||||
|
if c.Mldsa65Seed != nil {
|
||||||
|
_, key := mldsa65.NewKeyFromSeed((*[32]byte)(c.Mldsa65Seed))
|
||||||
|
config.Mldsa65Key = key.Bytes()
|
||||||
|
}
|
||||||
if c.LimitFallbackUpload != nil {
|
if c.LimitFallbackUpload != nil {
|
||||||
config.LimitFallbackUpload.AfterBytes = c.LimitFallbackUpload.AfterBytes
|
config.LimitFallbackUpload.AfterBytes = c.LimitFallbackUpload.AfterBytes
|
||||||
config.LimitFallbackUpload.BytesPerSec = c.LimitFallbackUpload.BytesPerSec
|
config.LimitFallbackUpload.BytesPerSec = c.LimitFallbackUpload.BytesPerSec
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.35.1
|
// protoc-gen-go v1.35.1
|
||||||
// protoc v5.29.4
|
// protoc v5.28.2
|
||||||
// source: transport/internet/reality/config.proto
|
// source: transport/internet/reality/config.proto
|
||||||
|
|
||||||
package reality
|
package reality
|
||||||
@@ -35,15 +35,17 @@ type Config struct {
|
|||||||
MaxClientVer []byte `protobuf:"bytes,8,opt,name=max_client_ver,json=maxClientVer,proto3" json:"max_client_ver,omitempty"`
|
MaxClientVer []byte `protobuf:"bytes,8,opt,name=max_client_ver,json=maxClientVer,proto3" json:"max_client_ver,omitempty"`
|
||||||
MaxTimeDiff uint64 `protobuf:"varint,9,opt,name=max_time_diff,json=maxTimeDiff,proto3" json:"max_time_diff,omitempty"`
|
MaxTimeDiff uint64 `protobuf:"varint,9,opt,name=max_time_diff,json=maxTimeDiff,proto3" json:"max_time_diff,omitempty"`
|
||||||
ShortIds [][]byte `protobuf:"bytes,10,rep,name=short_ids,json=shortIds,proto3" json:"short_ids,omitempty"`
|
ShortIds [][]byte `protobuf:"bytes,10,rep,name=short_ids,json=shortIds,proto3" json:"short_ids,omitempty"`
|
||||||
|
Mldsa65Seed []byte `protobuf:"bytes,11,opt,name=mldsa65_seed,json=mldsa65Seed,proto3" json:"mldsa65_seed,omitempty"`
|
||||||
|
LimitFallbackUpload *LimitFallback `protobuf:"bytes,12,opt,name=limit_fallback_upload,json=limitFallbackUpload,proto3" json:"limit_fallback_upload,omitempty"`
|
||||||
|
LimitFallbackDownload *LimitFallback `protobuf:"bytes,13,opt,name=limit_fallback_download,json=limitFallbackDownload,proto3" json:"limit_fallback_download,omitempty"`
|
||||||
Fingerprint string `protobuf:"bytes,21,opt,name=Fingerprint,proto3" json:"Fingerprint,omitempty"`
|
Fingerprint string `protobuf:"bytes,21,opt,name=Fingerprint,proto3" json:"Fingerprint,omitempty"`
|
||||||
ServerName string `protobuf:"bytes,22,opt,name=server_name,json=serverName,proto3" json:"server_name,omitempty"`
|
ServerName string `protobuf:"bytes,22,opt,name=server_name,json=serverName,proto3" json:"server_name,omitempty"`
|
||||||
PublicKey []byte `protobuf:"bytes,23,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
|
PublicKey []byte `protobuf:"bytes,23,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
|
||||||
ShortId []byte `protobuf:"bytes,24,opt,name=short_id,json=shortId,proto3" json:"short_id,omitempty"`
|
ShortId []byte `protobuf:"bytes,24,opt,name=short_id,json=shortId,proto3" json:"short_id,omitempty"`
|
||||||
SpiderX string `protobuf:"bytes,25,opt,name=spider_x,json=spiderX,proto3" json:"spider_x,omitempty"`
|
Mldsa65Verify []byte `protobuf:"bytes,25,opt,name=mldsa65_verify,json=mldsa65Verify,proto3" json:"mldsa65_verify,omitempty"`
|
||||||
SpiderY []int64 `protobuf:"varint,26,rep,packed,name=spider_y,json=spiderY,proto3" json:"spider_y,omitempty"`
|
SpiderX string `protobuf:"bytes,26,opt,name=spider_x,json=spiderX,proto3" json:"spider_x,omitempty"`
|
||||||
MasterKeyLog string `protobuf:"bytes,27,opt,name=master_key_log,json=masterKeyLog,proto3" json:"master_key_log,omitempty"`
|
SpiderY []int64 `protobuf:"varint,27,rep,packed,name=spider_y,json=spiderY,proto3" json:"spider_y,omitempty"`
|
||||||
LimitFallbackUpload *LimitFallback `protobuf:"bytes,28,opt,name=limit_fallback_upload,json=limitFallbackUpload,proto3" json:"limit_fallback_upload,omitempty"`
|
MasterKeyLog string `protobuf:"bytes,31,opt,name=master_key_log,json=masterKeyLog,proto3" json:"master_key_log,omitempty"`
|
||||||
LimitFallbackDownload *LimitFallback `protobuf:"bytes,29,opt,name=limit_fallback_download,json=limitFallbackDownload,proto3" json:"limit_fallback_download,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@@ -146,6 +148,27 @@ func (x *Config) GetShortIds() [][]byte {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetMldsa65Seed() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.Mldsa65Seed
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetLimitFallbackUpload() *LimitFallback {
|
||||||
|
if x != nil {
|
||||||
|
return x.LimitFallbackUpload
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetLimitFallbackDownload() *LimitFallback {
|
||||||
|
if x != nil {
|
||||||
|
return x.LimitFallbackDownload
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (x *Config) GetFingerprint() string {
|
func (x *Config) GetFingerprint() string {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Fingerprint
|
return x.Fingerprint
|
||||||
@@ -174,6 +197,13 @@ func (x *Config) GetShortId() []byte {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetMldsa65Verify() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.Mldsa65Verify
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (x *Config) GetSpiderX() string {
|
func (x *Config) GetSpiderX() string {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.SpiderX
|
return x.SpiderX
|
||||||
@@ -195,20 +225,6 @@ func (x *Config) GetMasterKeyLog() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetLimitFallbackUpload() *LimitFallback {
|
|
||||||
if x != nil {
|
|
||||||
return x.LimitFallbackUpload
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetLimitFallbackDownload() *LimitFallback {
|
|
||||||
if x != nil {
|
|
||||||
return x.LimitFallbackDownload
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type LimitFallback struct {
|
type LimitFallback struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -277,7 +293,7 @@ var file_transport_internet_reality_config_proto_rawDesc = []byte{
|
|||||||
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6e,
|
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6e,
|
||||||
0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1f, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1f, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||||
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
|
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
|
||||||
0x65, 0x74, 0x2e, 0x72, 0x65, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x22, 0xce, 0x05, 0x0a, 0x06, 0x43,
|
0x65, 0x74, 0x2e, 0x72, 0x65, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x22, 0x98, 0x06, 0x0a, 0x06, 0x43,
|
||||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x68, 0x6f, 0x77, 0x18, 0x01, 0x20,
|
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x68, 0x6f, 0x77, 0x18, 0x01, 0x20,
|
||||||
0x01, 0x28, 0x08, 0x52, 0x04, 0x73, 0x68, 0x6f, 0x77, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73,
|
0x01, 0x28, 0x08, 0x52, 0x04, 0x73, 0x68, 0x6f, 0x77, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73,
|
||||||
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a,
|
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a,
|
||||||
@@ -296,50 +312,55 @@ var file_transport_internet_reality_config_proto_rawDesc = []byte{
|
|||||||
0x65, 0x5f, 0x64, 0x69, 0x66, 0x66, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61,
|
0x65, 0x5f, 0x64, 0x69, 0x66, 0x66, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61,
|
||||||
0x78, 0x54, 0x69, 0x6d, 0x65, 0x44, 0x69, 0x66, 0x66, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x68, 0x6f,
|
0x78, 0x54, 0x69, 0x6d, 0x65, 0x44, 0x69, 0x66, 0x66, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x68, 0x6f,
|
||||||
0x72, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x68,
|
0x72, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x68,
|
||||||
0x6f, 0x72, 0x74, 0x49, 0x64, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72,
|
0x6f, 0x72, 0x74, 0x49, 0x64, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x6c, 0x64, 0x73, 0x61, 0x36,
|
||||||
0x70, 0x72, 0x69, 0x6e, 0x74, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x46, 0x69, 0x6e,
|
0x35, 0x5f, 0x73, 0x65, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x6d, 0x6c,
|
||||||
0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76,
|
0x64, 0x73, 0x61, 0x36, 0x35, 0x53, 0x65, 0x65, 0x64, 0x12, 0x62, 0x0a, 0x15, 0x6c, 0x69, 0x6d,
|
||||||
0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73,
|
0x69, 0x74, 0x5f, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x75, 0x70, 0x6c, 0x6f,
|
||||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62,
|
0x61, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||||
0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70,
|
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
|
||||||
0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x68, 0x6f, 0x72,
|
0x65, 0x74, 0x2e, 0x72, 0x65, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x2e, 0x4c, 0x69, 0x6d, 0x69, 0x74,
|
||||||
0x74, 0x5f, 0x69, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x73, 0x68, 0x6f, 0x72,
|
0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x13, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x46,
|
||||||
0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x78, 0x18,
|
0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x66, 0x0a,
|
||||||
0x19, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x69, 0x64, 0x65, 0x72, 0x58, 0x12, 0x19,
|
0x17, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f,
|
||||||
0x0a, 0x08, 0x73, 0x70, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x79, 0x18, 0x1a, 0x20, 0x03, 0x28, 0x03,
|
0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e,
|
||||||
0x52, 0x07, 0x73, 0x70, 0x69, 0x64, 0x65, 0x72, 0x59, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x61, 0x73,
|
|
||||||
0x74, 0x65, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x6c, 0x6f, 0x67, 0x18, 0x1b, 0x20, 0x01, 0x28,
|
|
||||||
0x09, 0x52, 0x0c, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x4c, 0x6f, 0x67, 0x12,
|
|
||||||
0x62, 0x0a, 0x15, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
|
|
||||||
0x6b, 0x5f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e,
|
|
||||||
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e,
|
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e,
|
||||||
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x72, 0x65, 0x61, 0x6c, 0x69, 0x74, 0x79,
|
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x72, 0x65, 0x61, 0x6c, 0x69, 0x74, 0x79,
|
||||||
0x2e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x13,
|
0x2e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x15,
|
||||||
0x6c, 0x69, 0x6d, 0x69, 0x74, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x55, 0x70, 0x6c,
|
0x6c, 0x69, 0x6d, 0x69, 0x74, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x44, 0x6f, 0x77,
|
||||||
0x6f, 0x61, 0x64, 0x12, 0x66, 0x0a, 0x17, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x66, 0x61, 0x6c,
|
0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70,
|
||||||
0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x1d,
|
0x72, 0x69, 0x6e, 0x74, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x46, 0x69, 0x6e, 0x67,
|
||||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e,
|
0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65,
|
||||||
0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x72,
|
0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65,
|
||||||
0x65, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x2e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x46, 0x61, 0x6c, 0x6c,
|
0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c,
|
||||||
0x62, 0x61, 0x63, 0x6b, 0x52, 0x15, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x46, 0x61, 0x6c, 0x6c, 0x62,
|
0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75,
|
||||||
0x61, 0x63, 0x6b, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x83, 0x01, 0x0a, 0x0d,
|
0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x68, 0x6f, 0x72, 0x74,
|
||||||
0x4c, 0x69, 0x6d, 0x69, 0x74, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x1f, 0x0a,
|
0x5f, 0x69, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x73, 0x68, 0x6f, 0x72, 0x74,
|
||||||
0x0b, 0x61, 0x66, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01,
|
0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x6c, 0x64, 0x73, 0x61, 0x36, 0x35, 0x5f, 0x76, 0x65,
|
||||||
0x28, 0x04, 0x52, 0x0a, 0x61, 0x66, 0x74, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x22,
|
0x72, 0x69, 0x66, 0x79, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x6d, 0x6c, 0x64, 0x73,
|
||||||
0x0a, 0x0d, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x18,
|
0x61, 0x36, 0x35, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x69,
|
||||||
0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, 0x50, 0x65, 0x72, 0x53,
|
0x64, 0x65, 0x72, 0x5f, 0x78, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x69,
|
||||||
0x65, 0x63, 0x12, 0x2d, 0x0a, 0x13, 0x62, 0x75, 0x72, 0x73, 0x74, 0x5f, 0x62, 0x79, 0x74, 0x65,
|
0x64, 0x65, 0x72, 0x58, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x79,
|
||||||
0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52,
|
0x18, 0x1b, 0x20, 0x03, 0x28, 0x03, 0x52, 0x07, 0x73, 0x70, 0x69, 0x64, 0x65, 0x72, 0x59, 0x12,
|
||||||
0x10, 0x62, 0x75, 0x72, 0x73, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x50, 0x65, 0x72, 0x53, 0x65,
|
0x24, 0x0a, 0x0e, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x6c, 0x6f,
|
||||||
0x63, 0x42, 0x7f, 0x0a, 0x23, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72,
|
0x67, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b,
|
||||||
0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
|
0x65, 0x79, 0x4c, 0x6f, 0x67, 0x22, 0x83, 0x01, 0x0a, 0x0d, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x46,
|
||||||
0x2e, 0x72, 0x65, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x01, 0x5a, 0x34, 0x67, 0x69, 0x74, 0x68,
|
0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x66, 0x74, 0x65, 0x72,
|
||||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79,
|
0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x61, 0x66,
|
||||||
0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f,
|
0x74, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x62, 0x79, 0x74, 0x65,
|
||||||
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x69, 0x74, 0x79,
|
0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52,
|
||||||
0xaa, 0x02, 0x1f, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
|
0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x12, 0x2d, 0x0a, 0x13,
|
||||||
0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x52, 0x65, 0x61, 0x6c, 0x69,
|
0x62, 0x75, 0x72, 0x73, 0x74, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f,
|
||||||
0x74, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x73, 0x65, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x62, 0x75, 0x72, 0x73, 0x74,
|
||||||
|
0x42, 0x79, 0x74, 0x65, 0x73, 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x42, 0x7f, 0x0a, 0x23, 0x63,
|
||||||
|
0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
|
||||||
|
0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x72, 0x65, 0x61, 0x6c, 0x69,
|
||||||
|
0x74, 0x79, 0x50, 0x01, 0x5a, 0x34, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
|
||||||
|
0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f,
|
||||||
|
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
|
||||||
|
0x65, 0x74, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x69, 0x74, 0x79, 0xaa, 0x02, 0x1f, 0x58, 0x72, 0x61,
|
||||||
|
0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65,
|
||||||
|
0x72, 0x6e, 0x65, 0x74, 0x2e, 0x52, 0x65, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72,
|
||||||
|
0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@@ -18,16 +18,19 @@ message Config {
|
|||||||
uint64 max_time_diff = 9;
|
uint64 max_time_diff = 9;
|
||||||
repeated bytes short_ids = 10;
|
repeated bytes short_ids = 10;
|
||||||
|
|
||||||
|
bytes mldsa65_seed = 11;
|
||||||
|
LimitFallback limit_fallback_upload = 12;
|
||||||
|
LimitFallback limit_fallback_download = 13;
|
||||||
|
|
||||||
string Fingerprint = 21;
|
string Fingerprint = 21;
|
||||||
string server_name = 22;
|
string server_name = 22;
|
||||||
bytes public_key = 23;
|
bytes public_key = 23;
|
||||||
bytes short_id = 24;
|
bytes short_id = 24;
|
||||||
string spider_x = 25;
|
bytes mldsa65_verify = 25;
|
||||||
repeated int64 spider_y = 26;
|
string spider_x = 26;
|
||||||
string master_key_log = 27;
|
repeated int64 spider_y = 27;
|
||||||
|
|
||||||
LimitFallback limit_fallback_upload = 28;
|
string master_key_log = 31;
|
||||||
LimitFallback limit_fallback_download = 29;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message LimitFallback {
|
message LimitFallback {
|
||||||
|
@@ -23,6 +23,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/cloudflare/circl/sign/mldsa/mldsa65"
|
||||||
utls "github.com/refraction-networking/utls"
|
utls "github.com/refraction-networking/utls"
|
||||||
"github.com/xtls/reality"
|
"github.com/xtls/reality"
|
||||||
"github.com/xtls/xray-core/common/crypto"
|
"github.com/xtls/xray-core/common/crypto"
|
||||||
@@ -56,6 +57,7 @@ func Server(c net.Conn, config *reality.Config) (net.Conn, error) {
|
|||||||
|
|
||||||
type UConn struct {
|
type UConn struct {
|
||||||
*utls.UConn
|
*utls.UConn
|
||||||
|
Config *Config
|
||||||
ServerName string
|
ServerName string
|
||||||
AuthKey []byte
|
AuthKey []byte
|
||||||
Verified bool
|
Verified bool
|
||||||
@@ -73,14 +75,32 @@ func (c *UConn) HandshakeAddress() net.Address {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *UConn) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
func (c *UConn) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||||
|
if c.Config.Show {
|
||||||
|
localAddr := c.LocalAddr().String()
|
||||||
|
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")
|
p, _ := reflect.TypeOf(c.Conn).Elem().FieldByName("peerCertificates")
|
||||||
certs := *(*([]*x509.Certificate))(unsafe.Pointer(uintptr(unsafe.Pointer(c.Conn)) + p.Offset))
|
certs := *(*([]*x509.Certificate))(unsafe.Pointer(uintptr(unsafe.Pointer(c.Conn)) + p.Offset))
|
||||||
if pub, ok := certs[0].PublicKey.(ed25519.PublicKey); ok {
|
if pub, ok := certs[0].PublicKey.(ed25519.PublicKey); ok {
|
||||||
h := hmac.New(sha512.New, c.AuthKey)
|
h := hmac.New(sha512.New, c.AuthKey)
|
||||||
h.Write(pub)
|
h.Write(pub)
|
||||||
if bytes.Equal(h.Sum(nil), certs[0].Signature) {
|
if bytes.Equal(h.Sum(nil), certs[0].Signature) {
|
||||||
c.Verified = true
|
if len(c.Config.Mldsa65Verify) > 0 {
|
||||||
return nil
|
if len(certs[0].Extensions) > 0 {
|
||||||
|
h.Write(c.HandshakeState.Hello.Raw)
|
||||||
|
h.Write(c.HandshakeState.ServerHello.Raw)
|
||||||
|
verify, _ := mldsa65.Scheme().UnmarshalBinaryPublicKey(c.Config.Mldsa65Verify)
|
||||||
|
if mldsa65.Verify(verify.(*mldsa65.PublicKey), h.Sum(nil), nil, certs[0].Extensions[0].Value) {
|
||||||
|
c.Verified = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.Verified = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
opts := x509.VerifyOptions{
|
opts := x509.VerifyOptions{
|
||||||
@@ -98,7 +118,9 @@ func (c *UConn) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x50
|
|||||||
|
|
||||||
func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destination) (net.Conn, error) {
|
func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destination) (net.Conn, error) {
|
||||||
localAddr := c.LocalAddr().String()
|
localAddr := c.LocalAddr().String()
|
||||||
uConn := &UConn{}
|
uConn := &UConn{
|
||||||
|
Config: config,
|
||||||
|
}
|
||||||
utlsConfig := &utls.Config{
|
utlsConfig := &utls.Config{
|
||||||
VerifyPeerCertificate: uConn.VerifyPeerCertificate,
|
VerifyPeerCertificate: uConn.VerifyPeerCertificate,
|
||||||
ServerName: config.ServerName,
|
ServerName: config.ServerName,
|
||||||
@@ -127,16 +149,20 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
|
|||||||
binary.BigEndian.PutUint32(hello.SessionId[4:], uint32(time.Now().Unix()))
|
binary.BigEndian.PutUint32(hello.SessionId[4:], uint32(time.Now().Unix()))
|
||||||
copy(hello.SessionId[8:], config.ShortId)
|
copy(hello.SessionId[8:], config.ShortId)
|
||||||
if config.Show {
|
if config.Show {
|
||||||
errors.LogInfo(ctx, fmt.Sprintf("REALITY localAddr: %v\thello.SessionId[:16]: %v\n", localAddr, hello.SessionId[:16]))
|
fmt.Printf("REALITY localAddr: %v\thello.SessionId[:16]: %v\n", localAddr, hello.SessionId[:16])
|
||||||
}
|
}
|
||||||
publicKey, err := ecdh.X25519().NewPublicKey(config.PublicKey)
|
publicKey, err := ecdh.X25519().NewPublicKey(config.PublicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("REALITY: publicKey == nil")
|
return nil, errors.New("REALITY: publicKey == nil")
|
||||||
}
|
}
|
||||||
if uConn.HandshakeState.State13.KeyShareKeys.Ecdhe == nil {
|
ecdhe := uConn.HandshakeState.State13.KeyShareKeys.Ecdhe
|
||||||
|
if ecdhe == nil {
|
||||||
|
ecdhe = uConn.HandshakeState.State13.KeyShareKeys.MlkemEcdhe
|
||||||
|
}
|
||||||
|
if ecdhe == nil {
|
||||||
return nil, errors.New("Current fingerprint ", uConn.ClientHelloID.Client, uConn.ClientHelloID.Version, " does not support TLS 1.3, REALITY handshake cannot establish.")
|
return nil, errors.New("Current fingerprint ", uConn.ClientHelloID.Client, uConn.ClientHelloID.Version, " does not support TLS 1.3, REALITY handshake cannot establish.")
|
||||||
}
|
}
|
||||||
uConn.AuthKey, _ = uConn.HandshakeState.State13.KeyShareKeys.Ecdhe.ECDH(publicKey)
|
uConn.AuthKey, _ = ecdhe.ECDH(publicKey)
|
||||||
if uConn.AuthKey == nil {
|
if uConn.AuthKey == nil {
|
||||||
return nil, errors.New("REALITY: SharedKey == nil")
|
return nil, errors.New("REALITY: SharedKey == nil")
|
||||||
}
|
}
|
||||||
@@ -146,7 +172,7 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
|
|||||||
block, _ := aes.NewCipher(uConn.AuthKey)
|
block, _ := aes.NewCipher(uConn.AuthKey)
|
||||||
aead, _ := cipher.NewGCM(block)
|
aead, _ := cipher.NewGCM(block)
|
||||||
if config.Show {
|
if config.Show {
|
||||||
errors.LogInfo(ctx, fmt.Sprintf("REALITY localAddr: %v\tuConn.AuthKey[:16]: %v\tAEAD: %T\n", localAddr, uConn.AuthKey[:16], aead))
|
fmt.Printf("REALITY localAddr: %v\tuConn.AuthKey[:16]: %v\tAEAD: %T\n", localAddr, uConn.AuthKey[:16], aead)
|
||||||
}
|
}
|
||||||
aead.Seal(hello.SessionId[:0], hello.Random[20:], hello.SessionId[:16], hello.Raw)
|
aead.Seal(hello.SessionId[:0], hello.Random[20:], hello.SessionId[:16], hello.Raw)
|
||||||
copy(hello.Raw[39:], hello.SessionId)
|
copy(hello.Raw[39:], hello.SessionId)
|
||||||
@@ -155,14 +181,14 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if config.Show {
|
if config.Show {
|
||||||
errors.LogInfo(ctx, fmt.Sprintf("REALITY localAddr: %v\tuConn.Verified: %v\n", localAddr, uConn.Verified))
|
fmt.Printf("REALITY localAddr: %v\tuConn.Verified: %v\n", localAddr, uConn.Verified)
|
||||||
}
|
}
|
||||||
if !uConn.Verified {
|
if !uConn.Verified {
|
||||||
go func() {
|
go func() {
|
||||||
client := &http.Client{
|
client := &http.Client{
|
||||||
Transport: &http2.Transport{
|
Transport: &http2.Transport{
|
||||||
DialTLSContext: func(ctx context.Context, network, addr string, cfg *gotls.Config) (net.Conn, error) {
|
DialTLSContext: func(ctx context.Context, network, addr string, cfg *gotls.Config) (net.Conn, error) {
|
||||||
errors.LogInfo(ctx, fmt.Sprintf("REALITY localAddr: %v\tDialTLSContext\n", localAddr))
|
fmt.Printf("REALITY localAddr: %v\tDialTLSContext\n", localAddr)
|
||||||
return uConn, nil
|
return uConn, nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -199,7 +225,7 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
|
|||||||
}
|
}
|
||||||
req.Header.Set("User-Agent", fingerprint.Client) // TODO: User-Agent map
|
req.Header.Set("User-Agent", fingerprint.Client) // TODO: User-Agent map
|
||||||
if first && config.Show {
|
if first && config.Show {
|
||||||
errors.LogInfo(ctx, fmt.Sprintf("REALITY localAddr: %v\treq.UserAgent(): %v\n", localAddr, req.UserAgent()))
|
fmt.Printf("REALITY localAddr: %v\treq.UserAgent(): %v\n", localAddr, req.UserAgent())
|
||||||
}
|
}
|
||||||
times := 1
|
times := 1
|
||||||
if !first {
|
if !first {
|
||||||
@@ -227,9 +253,9 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
|
|||||||
}
|
}
|
||||||
req.URL.Path = getPathLocked(paths)
|
req.URL.Path = getPathLocked(paths)
|
||||||
if config.Show {
|
if config.Show {
|
||||||
errors.LogInfo(ctx, fmt.Sprintf("REALITY localAddr: %v\treq.Referer(): %v\n", localAddr, req.Referer()))
|
fmt.Printf("REALITY localAddr: %v\treq.Referer(): %v\n", localAddr, req.Referer())
|
||||||
errors.LogInfo(ctx, fmt.Sprintf("REALITY localAddr: %v\tlen(body): %v\n", localAddr, len(body)))
|
fmt.Printf("REALITY localAddr: %v\tlen(body): %v\n", localAddr, len(body))
|
||||||
errors.LogInfo(ctx, fmt.Sprintf("REALITY localAddr: %v\tlen(paths): %v\n", localAddr, len(paths)))
|
fmt.Printf("REALITY localAddr: %v\tlen(paths): %v\n", localAddr, len(paths))
|
||||||
}
|
}
|
||||||
maps.Unlock()
|
maps.Unlock()
|
||||||
if !first {
|
if !first {
|
||||||
|
@@ -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 config.TcpCongestion != "" {
|
||||||
if err := syscall.SetsockoptString(int(fd), syscall.SOL_TCP, syscall.TCP_CONGESTION, config.TcpCongestion); err != nil {
|
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)
|
return errors.New("failed to set TCP_CONGESTION", err)
|
||||||
|
@@ -3,6 +3,7 @@ package internet
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
gonet "net"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -87,14 +88,34 @@ func (d *DefaultSystemDialer) Dial(ctx context.Context, src net.Address, dest ne
|
|||||||
Dest: destAddr,
|
Dest: destAddr,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
goStdKeepAlive := time.Duration(0)
|
// Chrome defaults
|
||||||
if sockopt != nil && (sockopt.TcpKeepAliveInterval != 0 || sockopt.TcpKeepAliveIdle != 0) {
|
keepAliveConfig := gonet.KeepAliveConfig{
|
||||||
goStdKeepAlive = time.Duration(-1)
|
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{
|
dialer := &net.Dialer{
|
||||||
Timeout: time.Second * 16,
|
Timeout: time.Second * 16,
|
||||||
LocalAddr: resolveSrcAddr(dest.Network, src),
|
LocalAddr: resolveSrcAddr(dest.Network, src),
|
||||||
KeepAlive: goStdKeepAlive,
|
KeepAlive: keepAlive,
|
||||||
|
KeepAliveConfig: keepAliveConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
if sockopt != nil || len(d.controllers) > 0 {
|
if sockopt != nil || len(d.controllers) > 0 {
|
||||||
|
@@ -2,6 +2,7 @@ package internet
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
gonet "net"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -88,9 +89,25 @@ func (dl *DefaultListener) Listen(ctx context.Context, addr net.Addr, sockopt *S
|
|||||||
network = addr.Network()
|
network = addr.Network()
|
||||||
address = addr.String()
|
address = addr.String()
|
||||||
lc.Control = getControlFunc(ctx, sockopt, dl.controllers)
|
lc.Control = getControlFunc(ctx, sockopt, dl.controllers)
|
||||||
|
// default disable keepalive
|
||||||
|
lc.KeepAlive = -1
|
||||||
if sockopt != nil {
|
if sockopt != nil {
|
||||||
if sockopt.TcpKeepAliveInterval != 0 || sockopt.TcpKeepAliveIdle != 0 {
|
if sockopt.TcpKeepAliveIdle*sockopt.TcpKeepAliveInterval < 0 {
|
||||||
lc.KeepAlive = time.Duration(-1)
|
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 {
|
if sockopt.TcpMptcp {
|
||||||
lc.SetMultipathTCP(true)
|
lc.SetMultipathTCP(true)
|
||||||
|
@@ -44,6 +44,10 @@ func NewDispatcher(dispatcher routing.Dispatcher, callback ResponseCallback) *Di
|
|||||||
func (v *Dispatcher) RemoveRay() {
|
func (v *Dispatcher) RemoveRay() {
|
||||||
v.Lock()
|
v.Lock()
|
||||||
defer v.Unlock()
|
defer v.Unlock()
|
||||||
|
v.removeRay()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Dispatcher) removeRay() {
|
||||||
if v.conn != nil {
|
if v.conn != nil {
|
||||||
common.Interrupt(v.conn.link.Reader)
|
common.Interrupt(v.conn.link.Reader)
|
||||||
common.Close(v.conn.link.Writer)
|
common.Close(v.conn.link.Writer)
|
||||||
@@ -62,9 +66,15 @@ func (v *Dispatcher) getInboundRay(ctx context.Context, dest net.Destination) (*
|
|||||||
errors.LogInfo(ctx, "establishing new connection for ", dest)
|
errors.LogInfo(ctx, "establishing new connection for ", dest)
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
entry := &connEntry{}
|
||||||
removeRay := func() {
|
removeRay := func() {
|
||||||
cancel()
|
v.Lock()
|
||||||
v.RemoveRay()
|
defer v.Unlock()
|
||||||
|
// sometimes the entry is already removed by others, don't close again
|
||||||
|
if entry == v.conn {
|
||||||
|
cancel()
|
||||||
|
v.removeRay()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
timer := signal.CancelAfterInactivity(ctx, removeRay, time.Minute)
|
timer := signal.CancelAfterInactivity(ctx, removeRay, time.Minute)
|
||||||
|
|
||||||
@@ -73,7 +83,7 @@ func (v *Dispatcher) getInboundRay(ctx context.Context, dest net.Destination) (*
|
|||||||
return nil, errors.New("failed to dispatch request to ", dest).Base(err)
|
return nil, errors.New("failed to dispatch request to ", dest).Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
entry := &connEntry{
|
*entry = connEntry{
|
||||||
link: link,
|
link: link,
|
||||||
timer: timer,
|
timer: timer,
|
||||||
cancel: removeRay,
|
cancel: removeRay,
|
||||||
|
Reference in New Issue
Block a user