mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-08-22 17:46:48 +08:00
Compare commits
2 Commits
87fff12fd9
...
remove-wir
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5f48bc16d4 | ||
![]() |
58b754a7d3 |
3
.github/workflows/docker.yml
vendored
3
.github/workflows/docker.yml
vendored
@@ -38,9 +38,6 @@ 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."
|
||||||
|
17
README.md
17
README.md
@@ -6,13 +6,9 @@
|
|||||||
|
|
||||||
## Donation & NFTs
|
## Donation & NFTs
|
||||||
|
|
||||||
### [Collect a Project X NFT to support the development of Project X!](https://opensea.io/item/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/1)
|
|
||||||
|
|
||||||
[<img alt="Project X NFT" width="150px" src="https://raw2.seadn.io/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/7fa9ce900fb39b44226348db330e32/8b7fa9ce900fb39b44226348db330e32.svg" />](https://opensea.io/item/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/1)
|
|
||||||
|
|
||||||
- **ETH/USDT/USDC: `0xDc3Fe44F0f25D13CACb1C4896CD0D321df3146Ee`**
|
- **ETH/USDT/USDC: `0xDc3Fe44F0f25D13CACb1C4896CD0D321df3146Ee`**
|
||||||
- **REALITY NFT: https://opensea.io/item/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/2**
|
- **Project X NFT: [Announcement of NFTs by Project X](https://github.com/XTLS/Xray-core/discussions/3633)**
|
||||||
- **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)**
|
- **REALITY NFT: [XHTTP: Beyond REALITY](https://github.com/XTLS/Xray-core/discussions/4113)**
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
@@ -92,28 +88,25 @@
|
|||||||
- [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 & tvOS
|
- iOS & macOS arm64
|
||||||
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215) ([tvOS](https://apps.apple.com/us/app/happ-proxy-utility-for-tv/id6748297274))
|
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215)
|
||||||
- [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 & tvOS
|
- iOS & macOS arm64
|
||||||
- [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,12 +204,7 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, uint32, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Static host lookup
|
// Static host lookup
|
||||||
switch addrs, err := s.hosts.Lookup(domain, option); {
|
switch addrs := 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,8 +2,6 @@ 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"
|
||||||
@@ -33,15 +31,7 @@ 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:
|
||||||
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))
|
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)
|
||||||
@@ -68,51 +58,38 @@ func filterIP(ips []net.Address, option dns.IPOption) []net.Address {
|
|||||||
return filtered
|
return filtered
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *StaticHosts) lookupInternal(domain string) ([]net.Address, error) {
|
func (h *StaticHosts) lookupInternal(domain string) []net.Address {
|
||||||
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, nil
|
return nil
|
||||||
}
|
}
|
||||||
return ips, nil
|
return ips
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *StaticHosts) lookup(domain string, option dns.IPOption, maxDepth int) ([]net.Address, error) {
|
func (h *StaticHosts) lookup(domain string, option dns.IPOption, maxDepth int) []net.Address {
|
||||||
switch addrs, err := h.lookupInternal(domain); {
|
switch addrs := 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, nil
|
return addrs
|
||||||
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, err := h.lookup(addrs[0].Domain(), option, maxDepth-1)
|
unwrapped := h.lookup(addrs[0].Domain(), option, maxDepth-1)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if unwrapped != nil {
|
if unwrapped != nil {
|
||||||
return unwrapped, nil
|
return unwrapped
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return addrs, nil
|
return addrs
|
||||||
default: // IP record found, return a non-nil IP array
|
default: // IP record found, return a non-nil IP array
|
||||||
return filterIP(addrs, option), nil
|
return filterIP(addrs, option)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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, error) {
|
func (h *StaticHosts) Lookup(domain string, option dns.IPOption) []net.Address {
|
||||||
return h.lookup(domain, option, 5)
|
return h.lookup(domain, option, 5)
|
||||||
}
|
}
|
||||||
|
@@ -12,11 +12,6 @@ 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",
|
||||||
@@ -59,14 +54,7 @@ func TestStaticHosts(t *testing.T) {
|
|||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
{
|
{
|
||||||
_, err := hosts.Lookup("example.com.lan", dns.IPOption{})
|
ips := hosts.Lookup("example.com", 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,
|
||||||
})
|
})
|
||||||
@@ -79,7 +67,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,
|
||||||
})
|
})
|
||||||
@@ -92,7 +80,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,
|
||||||
})
|
})
|
||||||
@@ -105,7 +93,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,
|
||||||
})
|
})
|
||||||
@@ -118,7 +106,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,7 +161,6 @@ 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() {
|
||||||
@@ -204,9 +203,6 @@ 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
|
||||||
@@ -263,7 +259,6 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,8 +306,7 @@ 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, cancel := context.WithCancel(w.ctx)
|
ctx := w.ctx
|
||||||
conn.cancel = cancel
|
|
||||||
sid := session.NewID()
|
sid := session.NewID()
|
||||||
ctx = c.ContextWithID(ctx, sid)
|
ctx = c.ContextWithID(ctx, sid)
|
||||||
|
|
||||||
|
@@ -9,7 +9,6 @@ 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.IsFull() {
|
if w.client.Closed() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if w.client.ActiveConnections() < minConn {
|
if w.client.ActiveConnections() < minConn {
|
||||||
@@ -211,7 +211,6 @@ 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) {
|
||||||
@@ -245,7 +244,7 @@ func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *PortalWorker) heartbeat() error {
|
func (w *PortalWorker) heartbeat() error {
|
||||||
if w.Closed() {
|
if w.client.Closed() {
|
||||||
return errors.New("client worker stopped")
|
return errors.New("client worker stopped")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,21 +260,16 @@ 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
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
w.counter = (w.counter + 1) % 5
|
|
||||||
if w.draining || w.counter == 1 {
|
|
||||||
b, err := proto.Marshal(msg)
|
b, err := proto.Marshal(msg)
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
mb := buf.MergeBytes(nil, b)
|
mb := buf.MergeBytes(nil, b)
|
||||||
return w.writer.WriteMultiBuffer(mb)
|
return w.writer.WriteMultiBuffer(mb)
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *PortalWorker) IsFull() bool {
|
func (w *PortalWorker) IsFull() bool {
|
||||||
|
@@ -1,152 +0,0 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.35.1
|
|
||||||
// protoc v5.28.2
|
|
||||||
// source: app/version/config.proto
|
|
||||||
|
|
||||||
package version
|
|
||||||
|
|
||||||
import (
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
reflect "reflect"
|
|
||||||
sync "sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Verify that this generated code is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
|
||||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
|
||||||
)
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
CoreVersion string `protobuf:"bytes,1,opt,name=core_version,json=coreVersion,proto3" json:"core_version,omitempty"`
|
|
||||||
MinVersion string `protobuf:"bytes,2,opt,name=min_version,json=minVersion,proto3" json:"min_version,omitempty"`
|
|
||||||
MaxVersion string `protobuf:"bytes,3,opt,name=max_version,json=maxVersion,proto3" json:"max_version,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
|
||||||
*x = Config{}
|
|
||||||
mi := &file_app_version_config_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Config) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_app_version_config_proto_msgTypes[0]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
|
||||||
func (*Config) Descriptor() ([]byte, []int) {
|
|
||||||
return file_app_version_config_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetCoreVersion() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.CoreVersion
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetMinVersion() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.MinVersion
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetMaxVersion() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.MaxVersion
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_app_version_config_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
var file_app_version_config_proto_rawDesc = []byte{
|
|
||||||
0x0a, 0x18, 0x61, 0x70, 0x70, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x6f,
|
|
||||||
0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x78, 0x72, 0x61, 0x79,
|
|
||||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x6d, 0x0a, 0x06,
|
|
||||||
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x72, 0x65, 0x5f, 0x76,
|
|
||||||
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f,
|
|
||||||
0x72, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x69, 0x6e,
|
|
||||||
0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
|
|
||||||
0x6d, 0x69, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x61,
|
|
||||||
0x78, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
|
|
||||||
0x0a, 0x6d, 0x61, 0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x52, 0x0a, 0x14, 0x63,
|
|
||||||
0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x76, 0x65, 0x72, 0x73,
|
|
||||||
0x69, 0x6f, 0x6e, 0x50, 0x01, 0x5a, 0x25, 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, 0x61, 0x70, 0x70, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0xaa, 0x02, 0x10, 0x58,
|
|
||||||
0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x62,
|
|
||||||
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_app_version_config_proto_rawDescOnce sync.Once
|
|
||||||
file_app_version_config_proto_rawDescData = file_app_version_config_proto_rawDesc
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_app_version_config_proto_rawDescGZIP() []byte {
|
|
||||||
file_app_version_config_proto_rawDescOnce.Do(func() {
|
|
||||||
file_app_version_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_version_config_proto_rawDescData)
|
|
||||||
})
|
|
||||||
return file_app_version_config_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_app_version_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
|
||||||
var file_app_version_config_proto_goTypes = []any{
|
|
||||||
(*Config)(nil), // 0: xray.app.version.Config
|
|
||||||
}
|
|
||||||
var file_app_version_config_proto_depIdxs = []int32{
|
|
||||||
0, // [0:0] is the sub-list for method output_type
|
|
||||||
0, // [0:0] is the sub-list for method input_type
|
|
||||||
0, // [0:0] is the sub-list for extension type_name
|
|
||||||
0, // [0:0] is the sub-list for extension extendee
|
|
||||||
0, // [0:0] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_app_version_config_proto_init() }
|
|
||||||
func file_app_version_config_proto_init() {
|
|
||||||
if File_app_version_config_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: file_app_version_config_proto_rawDesc,
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 1,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 0,
|
|
||||||
},
|
|
||||||
GoTypes: file_app_version_config_proto_goTypes,
|
|
||||||
DependencyIndexes: file_app_version_config_proto_depIdxs,
|
|
||||||
MessageInfos: file_app_version_config_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_app_version_config_proto = out.File
|
|
||||||
file_app_version_config_proto_rawDesc = nil
|
|
||||||
file_app_version_config_proto_goTypes = nil
|
|
||||||
file_app_version_config_proto_depIdxs = nil
|
|
||||||
}
|
|
@@ -1,14 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package xray.app.version;
|
|
||||||
option csharp_namespace = "Xray.App.Version";
|
|
||||||
option go_package = "github.com/xtls/xray-core/app/version";
|
|
||||||
option java_package = "com.xray.app.version";
|
|
||||||
option java_multiple_files = true;
|
|
||||||
|
|
||||||
|
|
||||||
message Config {
|
|
||||||
string core_version = 1;
|
|
||||||
string min_version = 2;
|
|
||||||
string max_version = 3;
|
|
||||||
}
|
|
@@ -1,77 +0,0 @@
|
|||||||
package version
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"github.com/xtls/xray-core/common"
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Version struct {
|
|
||||||
config *Config
|
|
||||||
ctx context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(ctx context.Context, config *Config) (*Version, error) {
|
|
||||||
if config.MinVersion != "" {
|
|
||||||
result, err := compareVersions(config.MinVersion, config.CoreVersion)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if result > 0 {
|
|
||||||
return nil, errors.New("this config must be run on version ", config.MinVersion, " or higher")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if config.MaxVersion != "" {
|
|
||||||
result, err := compareVersions(config.MaxVersion, config.CoreVersion)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if result < 0 {
|
|
||||||
return nil, errors.New("this config should be run on version ", config.MaxVersion, " or lower")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &Version{config: config, ctx: ctx}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func compareVersions(v1, v2 string) (int, error) {
|
|
||||||
// Split version strings into components
|
|
||||||
v1Parts := strings.Split(v1, ".")
|
|
||||||
v2Parts := strings.Split(v2, ".")
|
|
||||||
|
|
||||||
// Pad shorter versions with zeros
|
|
||||||
for len(v1Parts) < len(v2Parts) {
|
|
||||||
v1Parts = append(v1Parts, "0")
|
|
||||||
}
|
|
||||||
for len(v2Parts) < len(v1Parts) {
|
|
||||||
v2Parts = append(v2Parts, "0")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compare each part
|
|
||||||
for i := 0; i < len(v1Parts); i++ {
|
|
||||||
// Convert parts to integers
|
|
||||||
n1, err := strconv.Atoi(v1Parts[i])
|
|
||||||
if err != nil {
|
|
||||||
return 0, errors.New("invalid version component ", v1Parts[i], " in ", v1)
|
|
||||||
}
|
|
||||||
n2, err := strconv.Atoi(v2Parts[i])
|
|
||||||
if err != nil {
|
|
||||||
return 0, errors.New("invalid version component ", v2Parts[i], " in ", v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
if n1 < n2 {
|
|
||||||
return -1, nil // v1 < v2
|
|
||||||
}
|
|
||||||
if n1 > n2 {
|
|
||||||
return 1, nil // v1 > v2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0, nil // v1 == v2
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
|
||||||
return New(ctx, config.(*Config))
|
|
||||||
}))
|
|
||||||
}
|
|
@@ -173,7 +173,6 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,7 +187,6 @@ 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,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,12 +209,9 @@ 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() {
|
||||||
defer m.timer.Stop()
|
timer := time.NewTicker(time.Second * 16)
|
||||||
|
defer timer.Stop()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@@ -225,7 +220,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 <-m.timer.C:
|
case <-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())
|
||||||
@@ -281,8 +276,6 @@ 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
|
||||||
@@ -296,12 +289,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() {
|
if m.IsFull() || m.Closed() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
sm := m.sessionManager
|
sm := m.sessionManager
|
||||||
s := sm.Allocate(&m.strategy)
|
s := sm.Allocate()
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@@ -201,12 +201,11 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,23 +226,18 @@ 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
|
||||||
}
|
}
|
||||||
if !w.sessionManager.Add(s) {
|
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)
|
||||||
err = buf.Copy(rr, s.output)
|
if err := buf.Copy(rr, s.output); err != nil {
|
||||||
|
buf.Copy(rr, buf.Discard)
|
||||||
if err != nil && buf.IsWriteError(err) {
|
return s.Close(false)
|
||||||
s.Close(false)
|
|
||||||
return buf.Copy(rr, buf.Discard)
|
|
||||||
}
|
}
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *ServerWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.BufferedReader) error {
|
func (w *ServerWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.BufferedReader) error {
|
||||||
@@ -310,11 +304,10 @@ func (w *ServerWorker) handleFrame(ctx context.Context, reader *buf.BufferedRead
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *ServerWorker) run(ctx context.Context) {
|
func (w *ServerWorker) run(ctx context.Context) {
|
||||||
reader := &buf.BufferedReader{Reader: w.link.Reader}
|
input := 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 {
|
||||||
@@ -325,6 +318,7 @@ 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,14 +50,11 @@ func (m *SessionManager) Count() int {
|
|||||||
return int(m.count)
|
return int(m.count)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *SessionManager) Allocate(Strategy *ClientStrategy) *Session {
|
func (m *SessionManager) Allocate() *Session {
|
||||||
m.Lock()
|
m.Lock()
|
||||||
defer m.Unlock()
|
defer m.Unlock()
|
||||||
|
|
||||||
MaxConcurrency := int(Strategy.MaxConcurrency)
|
if m.closed {
|
||||||
MaxConnection := uint16(Strategy.MaxConnection)
|
|
||||||
|
|
||||||
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(&ClientStrategy{})
|
s := m.Allocate()
|
||||||
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(&ClientStrategy{})
|
s = m.Allocate()
|
||||||
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(&ClientStrategy{})
|
s := m.Allocate()
|
||||||
|
|
||||||
if m.CloseIfNoSession() {
|
if m.CloseIfNoSession() {
|
||||||
t.Error("able to close")
|
t.Error("able to close")
|
||||||
|
@@ -1,112 +0,0 @@
|
|||||||
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 = 7
|
Version_y byte = 6
|
||||||
Version_z byte = 26
|
Version_z byte = 8
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@@ -42,24 +42,6 @@ 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
|
||||||
|
18
go.mod
18
go.mod
@@ -3,6 +3,7 @@ module github.com/xtls/xray-core
|
|||||||
go 1.24
|
go 1.24
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0
|
||||||
github.com/cloudflare/circl v1.6.1
|
github.com/cloudflare/circl v1.6.1
|
||||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344
|
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344
|
||||||
github.com/golang/mock v1.7.0-rc.1
|
github.com/golang/mock v1.7.0-rc.1
|
||||||
@@ -12,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.8.0
|
github.com/refraction-networking/utls v1.7.3
|
||||||
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-20250725142056-5b52a03d4fb7
|
github.com/xtls/reality v0.0.0-20250715055725-05a351a64521
|
||||||
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.74.2
|
google.golang.org/grpc v1.73.0
|
||||||
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
|
||||||
@@ -34,14 +35,13 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/andybalholm/brotli v1.0.6 // indirect
|
github.com/andybalholm/brotli v1.1.0 // 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-20200812162917-85c65e2d0165 // indirect
|
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // 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.4 // indirect
|
github.com/klauspost/compress v1.17.8 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.0.12 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.7 // 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 +52,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-20250528174236-200df99c418a // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // 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
|
||||||
)
|
)
|
||||||
|
69
go.sum
69
go.sum
@@ -1,17 +1,19 @@
|
|||||||
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0 h1:Wo41lDOevRJSGpevP+8Pk5bANX7fJacO2w04aqLiC5I=
|
||||||
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
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.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||||
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.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.2/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=
|
||||||
@@ -30,14 +32,10 @@ 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.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
|
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
||||||
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE=
|
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
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=
|
||||||
@@ -46,19 +44,16 @@ 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.8.0 h1:L38krhiTAyj9EeiQQa2sg+hYb4qwLCqdMcpZrRfbONE=
|
github.com/refraction-networking/utls v1.7.3 h1:L0WRhHY7Oq1T0zkdzVZMR6zWZv+sXbHB9zcuvsAEqCo=
|
||||||
github.com/refraction-networking/utls v1.8.0/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
|
github.com/refraction-networking/utls v1.7.3/go.mod h1:TUhh27RHMGtQvjQq+RyO11P6ZNQNBb3N0v7wsEjKAIQ=
|
||||||
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=
|
||||||
@@ -75,21 +70,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-20250725142056-5b52a03d4fb7 h1:Ript0vN+nSO33+Vj4n0mgNY5M+oOxFQJdrJ1VnwTBO0=
|
github.com/xtls/reality v0.0.0-20250715055725-05a351a64521 h1:hQQSzX6Y40nY1XT1TKAEpKwUHUUy3UvYKQIclLjYx9U=
|
||||||
github.com/xtls/reality v0.0.0-20250725142056-5b52a03d4fb7/go.mod h1:XxvnCCgBee4WWE0bc4E+a7wbk8gkJ/rS0vNVNtC5qp0=
|
github.com/xtls/reality v0.0.0-20250715055725-05a351a64521/go.mod h1:yD47RN65bDLZgyHWMfFDiqlzrq4usDMt/Xzsk6tMbhw=
|
||||||
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.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
|
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
||||||
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
|
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
||||||
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
|
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
|
||||||
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
|
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
|
||||||
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
|
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
|
||||||
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
|
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
|
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
|
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
|
||||||
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
|
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
|
||||||
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
|
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
|
||||||
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=
|
||||||
@@ -116,6 +111,7 @@ 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=
|
||||||
@@ -139,15 +135,14 @@ 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-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 h1:e0AIkUUhxyBKh6ssZNrAMeqhA7RKUj42346d1y02i2g=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||||
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
|
google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
|
||||||
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
|
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
|
||||||
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=
|
||||||
|
@@ -1,35 +1,26 @@
|
|||||||
package conf
|
package conf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/proxy/dokodemo"
|
"github.com/xtls/xray-core/proxy/dokodemo"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DokodemoConfig struct {
|
type DokodemoConfig struct {
|
||||||
Address *Address `json:"address"`
|
Host *Address `json:"address"`
|
||||||
Port uint16 `json:"port"`
|
PortValue uint16 `json:"port"`
|
||||||
PortMap map[string]string `json:"portMap"`
|
NetworkList *NetworkList `json:"network"`
|
||||||
Network *NetworkList `json:"network"`
|
Redirect bool `json:"followRedirect"`
|
||||||
FollowRedirect bool `json:"followRedirect"`
|
|
||||||
UserLevel uint32 `json:"userLevel"`
|
UserLevel uint32 `json:"userLevel"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *DokodemoConfig) Build() (proto.Message, error) {
|
func (v *DokodemoConfig) Build() (proto.Message, error) {
|
||||||
config := new(dokodemo.Config)
|
config := new(dokodemo.Config)
|
||||||
if v.Address != nil {
|
if v.Host != nil {
|
||||||
config.Address = v.Address.Build()
|
config.Address = v.Host.Build()
|
||||||
}
|
}
|
||||||
config.Port = uint32(v.Port)
|
config.Port = uint32(v.PortValue)
|
||||||
config.PortMap = v.PortMap
|
config.Networks = v.NetworkList.Build()
|
||||||
for _, v := range config.PortMap {
|
config.FollowRedirect = v.Redirect
|
||||||
if _, _, err := net.SplitHostPort(v); err != nil {
|
|
||||||
return nil, errors.New("invalid portMap: ", v).Base(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
config.Networks = v.Network.Build()
|
|
||||||
config.FollowRedirect = v.FollowRedirect
|
|
||||||
config.UserLevel = v.UserLevel
|
config.UserLevel = v.UserLevel
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
@@ -412,10 +412,6 @@ type TLSConfig struct {
|
|||||||
MasterKeyLog string `json:"masterKeyLog"`
|
MasterKeyLog string `json:"masterKeyLog"`
|
||||||
ServerNameToVerify string `json:"serverNameToVerify"`
|
ServerNameToVerify string `json:"serverNameToVerify"`
|
||||||
VerifyPeerCertInNames []string `json:"verifyPeerCertInNames"`
|
VerifyPeerCertInNames []string `json:"verifyPeerCertInNames"`
|
||||||
ECHServerKeys string `json:"echServerKeys"`
|
|
||||||
ECHConfigList string `json:"echConfigList"`
|
|
||||||
ECHForceQuery bool `json:"echForceQuery"`
|
|
||||||
ECHSocketSettings *SocketConfig `json:"echSockopt"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build implements Buildable.
|
// Build implements Buildable.
|
||||||
@@ -439,7 +435,7 @@ func (c *TLSConfig) Build() (proto.Message, error) {
|
|||||||
}
|
}
|
||||||
if len(config.NextProtocol) > 1 {
|
if len(config.NextProtocol) > 1 {
|
||||||
for _, p := range config.NextProtocol {
|
for _, p := range config.NextProtocol {
|
||||||
if tls.IsFromMitm(p) {
|
if tcp.IsFromMitm(p) {
|
||||||
return nil, errors.New(`only one element is allowed in "alpn" when using "fromMitm" in it`)
|
return nil, errors.New(`only one element is allowed in "alpn" when using "fromMitm" in it`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -487,23 +483,6 @@ func (c *TLSConfig) Build() (proto.Message, error) {
|
|||||||
}
|
}
|
||||||
config.VerifyPeerCertInNames = c.VerifyPeerCertInNames
|
config.VerifyPeerCertInNames = c.VerifyPeerCertInNames
|
||||||
|
|
||||||
if c.ECHServerKeys != "" {
|
|
||||||
EchPrivateKey, err := base64.StdEncoding.DecodeString(c.ECHServerKeys)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("invalid ECH Config", c.ECHServerKeys)
|
|
||||||
}
|
|
||||||
config.EchServerKeys = EchPrivateKey
|
|
||||||
}
|
|
||||||
config.EchForceQuery = c.ECHForceQuery
|
|
||||||
config.EchConfigList = c.ECHConfigList
|
|
||||||
if c.ECHSocketSettings != nil {
|
|
||||||
ss, err := c.ECHSocketSettings.Build()
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("Failed to build ech sockopt.").Base(err)
|
|
||||||
}
|
|
||||||
config.EchSocketSettings = ss
|
|
||||||
}
|
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -526,7 +505,6 @@ 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"`
|
||||||
@@ -536,7 +514,6 @@ type REALITYConfig struct {
|
|||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
PublicKey string `json:"publicKey"`
|
PublicKey string `json:"publicKey"`
|
||||||
ShortId string `json:"shortId"`
|
ShortId string `json:"shortId"`
|
||||||
Mldsa65Verify string `json:"mldsa65Verify"`
|
|
||||||
SpiderX string `json:"spiderX"`
|
SpiderX string `json:"spiderX"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -633,15 +610,6 @@ 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 c.Mldsa65Seed == c.PrivateKey {
|
|
||||||
return nil, errors.New(`"mldsa65Seed" and "privateKey" can not be the same value: `, 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
|
||||||
@@ -677,11 +645,6 @@ 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 = "/"
|
||||||
}
|
}
|
||||||
|
@@ -1,22 +0,0 @@
|
|||||||
package conf
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/xtls/xray-core/app/version"
|
|
||||||
"github.com/xtls/xray-core/core"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
type VersionConfig struct {
|
|
||||||
MinVersion string `json:"min"`
|
|
||||||
MaxVersion string `json:"max"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *VersionConfig) Build() (*version.Config, error) {
|
|
||||||
coreVersion := strconv.Itoa(int(core.Version_x)) + "." + strconv.Itoa(int(core.Version_y)) + "." + strconv.Itoa(int(core.Version_z))
|
|
||||||
|
|
||||||
return &version.Config{
|
|
||||||
CoreVersion: coreVersion,
|
|
||||||
MinVersion: c.MinVersion,
|
|
||||||
MaxVersion: c.MaxVersion,
|
|
||||||
}, nil
|
|
||||||
}
|
|
@@ -49,8 +49,6 @@ func (c *WireGuardPeerConfig) Build() (proto.Message, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type WireGuardConfig struct {
|
type WireGuardConfig struct {
|
||||||
IsClient bool `json:""`
|
|
||||||
|
|
||||||
NoKernelTun bool `json:"noKernelTun"`
|
NoKernelTun bool `json:"noKernelTun"`
|
||||||
SecretKey string `json:"secretKey"`
|
SecretKey string `json:"secretKey"`
|
||||||
Address []string `json:"address"`
|
Address []string `json:"address"`
|
||||||
@@ -117,7 +115,6 @@ func (c *WireGuardConfig) Build() (proto.Message, error) {
|
|||||||
return nil, errors.New("unsupported domain strategy: ", c.DomainStrategy)
|
return nil, errors.New("unsupported domain strategy: ", c.DomainStrategy)
|
||||||
}
|
}
|
||||||
|
|
||||||
config.IsClient = c.IsClient
|
|
||||||
config.NoKernelTun = c.NoKernelTun
|
config.NoKernelTun = c.NoKernelTun
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
|
@@ -21,7 +21,6 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
inboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{
|
inboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{
|
||||||
"tunnel": func() interface{} { return new(DokodemoConfig) },
|
|
||||||
"dokodemo-door": func() interface{} { return new(DokodemoConfig) },
|
"dokodemo-door": func() interface{} { return new(DokodemoConfig) },
|
||||||
"http": func() interface{} { return new(HTTPServerConfig) },
|
"http": func() interface{} { return new(HTTPServerConfig) },
|
||||||
"shadowsocks": func() interface{} { return new(ShadowsocksServerConfig) },
|
"shadowsocks": func() interface{} { return new(ShadowsocksServerConfig) },
|
||||||
@@ -30,14 +29,11 @@ var (
|
|||||||
"vless": func() interface{} { return new(VLessInboundConfig) },
|
"vless": func() interface{} { return new(VLessInboundConfig) },
|
||||||
"vmess": func() interface{} { return new(VMessInboundConfig) },
|
"vmess": func() interface{} { return new(VMessInboundConfig) },
|
||||||
"trojan": func() interface{} { return new(TrojanServerConfig) },
|
"trojan": func() interface{} { return new(TrojanServerConfig) },
|
||||||
"wireguard": func() interface{} { return &WireGuardConfig{IsClient: false} },
|
|
||||||
}, "protocol", "settings")
|
}, "protocol", "settings")
|
||||||
|
|
||||||
outboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{
|
outboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{
|
||||||
"block": func() interface{} { return new(BlackholeConfig) },
|
|
||||||
"blackhole": func() interface{} { return new(BlackholeConfig) },
|
"blackhole": func() interface{} { return new(BlackholeConfig) },
|
||||||
"loopback": func() interface{} { return new(LoopbackConfig) },
|
"loopback": func() interface{} { return new(LoopbackConfig) },
|
||||||
"direct": func() interface{} { return new(FreedomConfig) },
|
|
||||||
"freedom": func() interface{} { return new(FreedomConfig) },
|
"freedom": func() interface{} { return new(FreedomConfig) },
|
||||||
"http": func() interface{} { return new(HTTPClientConfig) },
|
"http": func() interface{} { return new(HTTPClientConfig) },
|
||||||
"shadowsocks": func() interface{} { return new(ShadowsocksClientConfig) },
|
"shadowsocks": func() interface{} { return new(ShadowsocksClientConfig) },
|
||||||
@@ -46,7 +42,7 @@ var (
|
|||||||
"vmess": func() interface{} { return new(VMessOutboundConfig) },
|
"vmess": func() interface{} { return new(VMessOutboundConfig) },
|
||||||
"trojan": func() interface{} { return new(TrojanClientConfig) },
|
"trojan": func() interface{} { return new(TrojanClientConfig) },
|
||||||
"dns": func() interface{} { return new(DNSOutboundConfig) },
|
"dns": func() interface{} { return new(DNSOutboundConfig) },
|
||||||
"wireguard": func() interface{} { return &WireGuardConfig{IsClient: true} },
|
"wireguard": func() interface{} { return new(WireGuardConfig) },
|
||||||
}, "protocol", "settings")
|
}, "protocol", "settings")
|
||||||
|
|
||||||
ctllog = log.New(os.Stderr, "xctl> ", 0)
|
ctllog = log.New(os.Stderr, "xctl> ", 0)
|
||||||
@@ -245,7 +241,7 @@ func (c *InboundDetourConfig) Build() (*core.InboundHandlerConfig, error) {
|
|||||||
return nil, errors.New("failed to load inbound detour config for protocol ", c.Protocol).Base(err)
|
return nil, errors.New("failed to load inbound detour config for protocol ", c.Protocol).Base(err)
|
||||||
}
|
}
|
||||||
if dokodemoConfig, ok := rawConfig.(*DokodemoConfig); ok {
|
if dokodemoConfig, ok := rawConfig.(*DokodemoConfig); ok {
|
||||||
receiverSettings.ReceiveOriginalDestination = dokodemoConfig.FollowRedirect
|
receiverSettings.ReceiveOriginalDestination = dokodemoConfig.Redirect
|
||||||
}
|
}
|
||||||
ts, err := rawConfig.(Buildable).Build()
|
ts, err := rawConfig.(Buildable).Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -383,7 +379,6 @@ type Config struct {
|
|||||||
FakeDNS *FakeDNSConfig `json:"fakeDns"`
|
FakeDNS *FakeDNSConfig `json:"fakeDns"`
|
||||||
Observatory *ObservatoryConfig `json:"observatory"`
|
Observatory *ObservatoryConfig `json:"observatory"`
|
||||||
BurstObservatory *BurstObservatoryConfig `json:"burstObservatory"`
|
BurstObservatory *BurstObservatoryConfig `json:"burstObservatory"`
|
||||||
Version *VersionConfig `json:"version"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) findInboundTag(tag string) int {
|
func (c *Config) findInboundTag(tag string) int {
|
||||||
@@ -452,10 +447,6 @@ func (c *Config) Override(o *Config, fn string) {
|
|||||||
c.BurstObservatory = o.BurstObservatory
|
c.BurstObservatory = o.BurstObservatory
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.Version != nil {
|
|
||||||
c.Version = o.Version
|
|
||||||
}
|
|
||||||
|
|
||||||
// update the Inbound in slice if the only one in override config has same tag
|
// update the Inbound in slice if the only one in override config has same tag
|
||||||
if len(o.InboundConfigs) > 0 {
|
if len(o.InboundConfigs) > 0 {
|
||||||
for i := range o.InboundConfigs {
|
for i := range o.InboundConfigs {
|
||||||
@@ -596,14 +587,6 @@ func (c *Config) Build() (*core.Config, error) {
|
|||||||
config.App = append(config.App, serial.ToTypedMessage(r))
|
config.App = append(config.App, serial.ToTypedMessage(r))
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Version != nil {
|
|
||||||
r, err := c.Version.Build()
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("failed to build version configuration").Base(err)
|
|
||||||
}
|
|
||||||
config.App = append(config.App, serial.ToTypedMessage(r))
|
|
||||||
}
|
|
||||||
|
|
||||||
var inbounds []InboundDetourConfig
|
var inbounds []InboundDetourConfig
|
||||||
|
|
||||||
if len(c.InboundConfigs) > 0 {
|
if len(c.InboundConfigs) > 0 {
|
||||||
|
@@ -23,8 +23,6 @@ var CmdAPI = &base.Command{
|
|||||||
cmdRemoveOutbounds,
|
cmdRemoveOutbounds,
|
||||||
cmdListInbounds,
|
cmdListInbounds,
|
||||||
cmdListOutbounds,
|
cmdListOutbounds,
|
||||||
cmdAddInboundUsers,
|
|
||||||
cmdRemoveInboundUsers,
|
|
||||||
cmdInboundUser,
|
cmdInboundUser,
|
||||||
cmdInboundUserCount,
|
cmdInboundUserCount,
|
||||||
cmdAddRules,
|
cmdAddRules,
|
||||||
|
@@ -1,144 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
|
||||||
|
|
||||||
handlerService "github.com/xtls/xray-core/app/proxyman/command"
|
|
||||||
cserial "github.com/xtls/xray-core/common/serial"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/core"
|
|
||||||
"github.com/xtls/xray-core/infra/conf"
|
|
||||||
"github.com/xtls/xray-core/infra/conf/serial"
|
|
||||||
"github.com/xtls/xray-core/proxy/shadowsocks"
|
|
||||||
"github.com/xtls/xray-core/proxy/shadowsocks_2022"
|
|
||||||
"github.com/xtls/xray-core/proxy/trojan"
|
|
||||||
vlessin "github.com/xtls/xray-core/proxy/vless/inbound"
|
|
||||||
vmessin "github.com/xtls/xray-core/proxy/vmess/inbound"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/main/commands/base"
|
|
||||||
)
|
|
||||||
|
|
||||||
var cmdAddInboundUsers = &base.Command{
|
|
||||||
CustomFlags: true,
|
|
||||||
UsageLine: "{{.Exec}} api adu [--server=127.0.0.1:8080] <c1.json> [c2.json]...",
|
|
||||||
Short: "Add users to inbounds",
|
|
||||||
Long: `
|
|
||||||
Add users to inbounds.
|
|
||||||
Arguments:
|
|
||||||
-s, -server
|
|
||||||
The API server address. Default 127.0.0.1:8080
|
|
||||||
-t, -timeout
|
|
||||||
Timeout seconds to call API. Default 3
|
|
||||||
Example:
|
|
||||||
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 c1.json c2.json
|
|
||||||
`,
|
|
||||||
Run: executeAddInboundUsers,
|
|
||||||
}
|
|
||||||
|
|
||||||
func executeAddInboundUsers(cmd *base.Command, args []string) {
|
|
||||||
setSharedFlags(cmd)
|
|
||||||
cmd.Flag.Parse(args)
|
|
||||||
unnamedArgs := cmd.Flag.Args()
|
|
||||||
inbs := extractInboundsConfig(unnamedArgs)
|
|
||||||
|
|
||||||
conn, ctx, close := dialAPIServer()
|
|
||||||
defer close()
|
|
||||||
client := handlerService.NewHandlerServiceClient(conn)
|
|
||||||
|
|
||||||
success := 0
|
|
||||||
for _, inb := range inbs {
|
|
||||||
success += executeInboundUserAction(ctx, client, inb, addInboundUserAction)
|
|
||||||
}
|
|
||||||
fmt.Println("Added", success, "user(s) in total.")
|
|
||||||
}
|
|
||||||
|
|
||||||
func addInboundUserAction(ctx context.Context, client handlerService.HandlerServiceClient, tag string, user *protocol.User) error {
|
|
||||||
fmt.Println("add user:", user.Email)
|
|
||||||
_, err := client.AlterInbound(ctx, &handlerService.AlterInboundRequest{
|
|
||||||
Tag: tag,
|
|
||||||
Operation: cserial.ToTypedMessage(
|
|
||||||
&handlerService.AddUserOperation{
|
|
||||||
User: user,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func extractInboundUsers(inb *core.InboundHandlerConfig) []*protocol.User {
|
|
||||||
if inb == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
inst, err := inb.ProxySettings.GetInstance()
|
|
||||||
if err != nil || inst == nil {
|
|
||||||
fmt.Println("failed to get inbound instance:", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
switch ty := inst.(type) {
|
|
||||||
case *vmessin.Config:
|
|
||||||
return ty.User
|
|
||||||
case *vlessin.Config:
|
|
||||||
return ty.Clients
|
|
||||||
case *trojan.ServerConfig:
|
|
||||||
return ty.Users
|
|
||||||
case *shadowsocks.ServerConfig:
|
|
||||||
return ty.Users
|
|
||||||
case *shadowsocks_2022.MultiUserServerConfig:
|
|
||||||
return ty.Users
|
|
||||||
default:
|
|
||||||
fmt.Println("unsupported inbound type")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func extractInboundsConfig(unnamedArgs []string) []conf.InboundDetourConfig {
|
|
||||||
ins := make([]conf.InboundDetourConfig, 0)
|
|
||||||
for _, arg := range unnamedArgs {
|
|
||||||
r, err := loadArg(arg)
|
|
||||||
if err != nil {
|
|
||||||
base.Fatalf("failed to load %s: %s", arg, err)
|
|
||||||
}
|
|
||||||
conf, err := serial.DecodeJSONConfig(r)
|
|
||||||
if err != nil {
|
|
||||||
base.Fatalf("failed to decode %s: %s", arg, err)
|
|
||||||
}
|
|
||||||
ins = append(ins, conf.InboundConfigs...)
|
|
||||||
}
|
|
||||||
return ins
|
|
||||||
}
|
|
||||||
|
|
||||||
func executeInboundUserAction(ctx context.Context, client handlerService.HandlerServiceClient, inb conf.InboundDetourConfig, action func(ctx context.Context, client handlerService.HandlerServiceClient, tag string, user *protocol.User) error) int {
|
|
||||||
success := 0
|
|
||||||
|
|
||||||
tag := inb.Tag
|
|
||||||
if len(tag) < 1 {
|
|
||||||
return success
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("processing inbound:", tag)
|
|
||||||
built, err := inb.Build()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("failed to build config:", err)
|
|
||||||
return success
|
|
||||||
}
|
|
||||||
|
|
||||||
users := extractInboundUsers(built)
|
|
||||||
if users == nil {
|
|
||||||
return success
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, user := range users {
|
|
||||||
if len(user.Email) < 1 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err := action(ctx, client, inb.Tag, user); err == nil {
|
|
||||||
fmt.Println("result: ok")
|
|
||||||
success += 1
|
|
||||||
} else {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return success
|
|
||||||
}
|
|
@@ -1,62 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
handlerService "github.com/xtls/xray-core/app/proxyman/command"
|
|
||||||
cserial "github.com/xtls/xray-core/common/serial"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/main/commands/base"
|
|
||||||
)
|
|
||||||
|
|
||||||
var cmdRemoveInboundUsers = &base.Command{
|
|
||||||
CustomFlags: true,
|
|
||||||
UsageLine: "{{.Exec}} api rmu [--server=127.0.0.1:8080] -tag=tag <email1> [email2]...",
|
|
||||||
Short: "Remove users from inbounds",
|
|
||||||
Long: `
|
|
||||||
Remove users from inbounds.
|
|
||||||
Arguments:
|
|
||||||
-s, -server
|
|
||||||
The API server address. Default 127.0.0.1:8080
|
|
||||||
-t, -timeout
|
|
||||||
Timeout seconds to call API. Default 3
|
|
||||||
-tag
|
|
||||||
Inbound tag
|
|
||||||
Example:
|
|
||||||
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 -tag="vless-in" "xray@love.com" ...
|
|
||||||
`,
|
|
||||||
Run: executeRemoveUsers,
|
|
||||||
}
|
|
||||||
|
|
||||||
func executeRemoveUsers(cmd *base.Command, args []string) {
|
|
||||||
setSharedFlags(cmd)
|
|
||||||
var tag string
|
|
||||||
cmd.Flag.StringVar(&tag, "tag", "", "")
|
|
||||||
cmd.Flag.Parse(args)
|
|
||||||
emails := cmd.Flag.Args()
|
|
||||||
if len(tag) < 1 {
|
|
||||||
base.Fatalf("inbound tag not specified")
|
|
||||||
}
|
|
||||||
|
|
||||||
conn, ctx, close := dialAPIServer()
|
|
||||||
defer close()
|
|
||||||
client := handlerService.NewHandlerServiceClient(conn)
|
|
||||||
|
|
||||||
success := 0
|
|
||||||
for _, email := range emails {
|
|
||||||
fmt.Println("remove user:", email)
|
|
||||||
_, err := client.AlterInbound(ctx, &handlerService.AlterInboundRequest{
|
|
||||||
Tag: tag,
|
|
||||||
Operation: cserial.ToTypedMessage(
|
|
||||||
&handlerService.RemoveUserOperation{
|
|
||||||
Email: email,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
if err == nil {
|
|
||||||
success += 1
|
|
||||||
} else {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Println("Removed", success, "user(s) in total.")
|
|
||||||
}
|
|
@@ -16,6 +16,5 @@ func init() {
|
|||||||
cmdUUID,
|
cmdUUID,
|
||||||
cmdX25519,
|
cmdX25519,
|
||||||
cmdWG,
|
cmdWG,
|
||||||
cmdMLDSA65,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -1,42 +0,0 @@
|
|||||||
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()))
|
|
||||||
}
|
|
@@ -1,26 +1,25 @@
|
|||||||
package tls
|
package tls
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/json"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/xtls/reality/hpke"
|
"github.com/OmarTariq612/goech"
|
||||||
|
"github.com/cloudflare/circl/hpke"
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/main/commands/base"
|
"github.com/xtls/xray-core/main/commands/base"
|
||||||
"github.com/xtls/xray-core/transport/internet/tls"
|
|
||||||
"golang.org/x/crypto/cryptobyte"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var cmdECH = &base.Command{
|
var cmdECH = &base.Command{
|
||||||
UsageLine: `{{.Exec}} tls ech [--serverName (string)] [--pem] [-i "ECHServerKeys (base64.StdEncoding)"]`,
|
UsageLine: `{{.Exec}} tls ech [--serverName (string)] [--json]`,
|
||||||
Short: `Generate TLS-ECH certificates`,
|
Short: `Generate TLS-ECH certificates`,
|
||||||
Long: `
|
Long: `
|
||||||
Generate TLS-ECH certificates.
|
Generate TLS-ECH certificates.
|
||||||
|
|
||||||
Set serverName to your custom string: {{.Exec}} tls ech --serverName (string)
|
Set serverName to your custom string: {{.Exec}} tls ech --serverName (string)
|
||||||
Generate into pem format: {{.Exec}} tls ech --pem
|
Generate into json format: {{.Exec}} tls ech --json
|
||||||
Restore ECHConfigs from ECHServerKeys: {{.Exec}} tls ech -i "ECHServerKeys (base64.StdEncoding)"
|
|
||||||
`, // Enable PQ signature schemes: {{.Exec}} tls ech --pq-signature-schemes-enabled
|
`, // Enable PQ signature schemes: {{.Exec}} tls ech --pq-signature-schemes-enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,66 +27,43 @@ func init() {
|
|||||||
cmdECH.Run = executeECH
|
cmdECH.Run = executeECH
|
||||||
}
|
}
|
||||||
|
|
||||||
var input_echServerKeys = cmdECH.Flag.String("i", "", "ECHServerKeys (base64.StdEncoding)")
|
var input_pqSignatureSchemesEnabled = cmdECH.Flag.Bool("pqSignatureSchemesEnabled", false, "")
|
||||||
|
|
||||||
// var input_pqSignatureSchemesEnabled = cmdECH.Flag.Bool("pqSignatureSchemesEnabled", false, "")
|
|
||||||
var input_serverName = cmdECH.Flag.String("serverName", "cloudflare-ech.com", "")
|
var input_serverName = cmdECH.Flag.String("serverName", "cloudflare-ech.com", "")
|
||||||
var input_pem = cmdECH.Flag.Bool("pem", false, "True == turn on pem output")
|
var input_json = cmdECH.Flag.Bool("json", false, "True == turn on json output")
|
||||||
|
|
||||||
func executeECH(cmd *base.Command, args []string) {
|
func executeECH(cmd *base.Command, args []string) {
|
||||||
var kem uint16
|
var kem hpke.KEM
|
||||||
|
|
||||||
// if *input_pqSignatureSchemesEnabled {
|
if *input_pqSignatureSchemesEnabled {
|
||||||
// kem = 0x30 // hpke.KEM_X25519_KYBER768_DRAFT00
|
kem = hpke.KEM_X25519_KYBER768_DRAFT00
|
||||||
// } else {
|
} else {
|
||||||
kem = hpke.DHKEM_X25519_HKDF_SHA256
|
kem = hpke.KEM_X25519_HKDF_SHA256
|
||||||
// }
|
}
|
||||||
|
|
||||||
echConfig, priv, err := tls.GenerateECHKeySet(0, *input_serverName, kem)
|
echKeySet, err := goech.GenerateECHKeySet(0, *input_serverName, kem)
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
var configBuffer, keyBuffer []byte
|
configBuffer, _ := echKeySet.ECHConfig.MarshalBinary()
|
||||||
if *input_echServerKeys == "" {
|
keyBuffer, _ := echKeySet.MarshalBinary()
|
||||||
configBytes, _ := tls.MarshalBinary(echConfig)
|
|
||||||
var b cryptobyte.Builder
|
|
||||||
b.AddUint16LengthPrefixed(func(child *cryptobyte.Builder) {
|
|
||||||
child.AddBytes(configBytes)
|
|
||||||
})
|
|
||||||
configBuffer, _ = b.Bytes()
|
|
||||||
var b2 cryptobyte.Builder
|
|
||||||
b2.AddUint16(uint16(len(priv)))
|
|
||||||
b2.AddBytes(priv)
|
|
||||||
b2.AddUint16(uint16(len(configBytes)))
|
|
||||||
b2.AddBytes(configBytes)
|
|
||||||
keyBuffer, _ = b2.Bytes()
|
|
||||||
} else {
|
|
||||||
keySetsByte, err := base64.StdEncoding.DecodeString(*input_echServerKeys)
|
|
||||||
if err != nil {
|
|
||||||
os.Stdout.WriteString("Failed to decode ECHServerKeys: " + err.Error() + "\n")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
keyBuffer = keySetsByte
|
|
||||||
KeySets, err := tls.ConvertToGoECHKeys(keySetsByte)
|
|
||||||
if err != nil {
|
|
||||||
os.Stdout.WriteString("Failed to decode ECHServerKeys: " + err.Error() + "\n")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var b cryptobyte.Builder
|
|
||||||
for _, keySet := range KeySets {
|
|
||||||
b.AddUint16LengthPrefixed(func(child *cryptobyte.Builder) {
|
|
||||||
child.AddBytes(keySet.Config)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
configBuffer, _ = b.Bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
if *input_pem {
|
|
||||||
configPEM := string(pem.EncodeToMemory(&pem.Block{Type: "ECH CONFIGS", Bytes: configBuffer}))
|
configPEM := string(pem.EncodeToMemory(&pem.Block{Type: "ECH CONFIGS", Bytes: configBuffer}))
|
||||||
keyPEM := string(pem.EncodeToMemory(&pem.Block{Type: "ECH KEYS", Bytes: keyBuffer}))
|
keyPEM := string(pem.EncodeToMemory(&pem.Block{Type: "ECH KEYS", Bytes: keyBuffer}))
|
||||||
|
if *input_json {
|
||||||
|
jECHConfigs := map[string]interface{}{
|
||||||
|
"configs": strings.Split(strings.TrimSpace(string(configPEM)), "\n"),
|
||||||
|
}
|
||||||
|
jECHKey := map[string]interface{}{
|
||||||
|
"key": strings.Split(strings.TrimSpace(string(keyPEM)), "\n"),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, i := range []map[string]interface{}{jECHConfigs, jECHKey} {
|
||||||
|
content, err := json.MarshalIndent(i, "", " ")
|
||||||
|
common.Must(err)
|
||||||
|
os.Stdout.Write(content)
|
||||||
|
os.Stdout.WriteString("\n")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
os.Stdout.WriteString(configPEM)
|
os.Stdout.WriteString(configPEM)
|
||||||
os.Stdout.WriteString(keyPEM)
|
os.Stdout.WriteString(keyPEM)
|
||||||
} else {
|
|
||||||
os.Stdout.WriteString("ECH config list: \n" + base64.StdEncoding.EncodeToString(configBuffer) + "\n")
|
|
||||||
os.Stdout.WriteString("ECH server keys: \n" + base64.StdEncoding.EncodeToString(keyBuffer) + "\n")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -40,12 +40,10 @@ 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +61,7 @@ func executePing(cmd *base.Command, args []string) {
|
|||||||
}
|
}
|
||||||
ip = v.IP
|
ip = v.IP
|
||||||
}
|
}
|
||||||
fmt.Println("Using IP: ", ip.String()+":"+strconv.Itoa(TargetPort))
|
fmt.Println("Using IP: ", ip.String())
|
||||||
|
|
||||||
fmt.Println("-------------------")
|
fmt.Println("-------------------")
|
||||||
fmt.Println("Pinging without SNI")
|
fmt.Println("Pinging without SNI")
|
||||||
@@ -74,7 +72,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{"h2", "http/1.1"},
|
NextProtos: []string{"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
|
||||||
@@ -100,7 +98,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{"h2", "http/1.1"},
|
NextProtos: []string{"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
|
||||||
@@ -108,33 +106,24 @@ 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("-------------------")
|
fmt.Println("Tls ping finished")
|
||||||
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 {
|
||||||
length += len(cert.Raw)
|
if len(cert.DNSNames) == 0 {
|
||||||
if len(cert.DNSNames) != 0 {
|
continue
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,13 +134,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("TLS Post-Quantum key exchange: ", PostQuantum, "("+curveID.String()+")")
|
fmt.Println("Post-Quantum key exchange:", PostQuantum, "("+curveID.String()+")")
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("TLS Post-Quantum key exchange: false (RSA Exchange)")
|
fmt.Println("Post-Quantum key exchange: false (RSA Exchange)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -28,7 +28,6 @@ type Config struct {
|
|||||||
|
|
||||||
Address *net.IPOrDomain `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
|
Address *net.IPOrDomain `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
|
||||||
Port uint32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
|
Port uint32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
|
||||||
PortMap map[string]string `protobuf:"bytes,3,rep,name=port_map,json=portMap,proto3" json:"port_map,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
|
||||||
// List of networks that the Dokodemo accepts.
|
// List of networks that the Dokodemo accepts.
|
||||||
Networks []net.Network `protobuf:"varint,7,rep,packed,name=networks,proto3,enum=xray.common.net.Network" json:"networks,omitempty"`
|
Networks []net.Network `protobuf:"varint,7,rep,packed,name=networks,proto3,enum=xray.common.net.Network" json:"networks,omitempty"`
|
||||||
FollowRedirect bool `protobuf:"varint,5,opt,name=follow_redirect,json=followRedirect,proto3" json:"follow_redirect,omitempty"`
|
FollowRedirect bool `protobuf:"varint,5,opt,name=follow_redirect,json=followRedirect,proto3" json:"follow_redirect,omitempty"`
|
||||||
@@ -79,13 +78,6 @@ func (x *Config) GetPort() uint32 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetPortMap() map[string]string {
|
|
||||||
if x != nil {
|
|
||||||
return x.PortMap
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetNetworks() []net.Network {
|
func (x *Config) GetNetworks() []net.Network {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Networks
|
return x.Networks
|
||||||
@@ -116,34 +108,26 @@ var file_proxy_dokodemo_config_proto_rawDesc = []byte{
|
|||||||
0x6d, 0x6f, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x61,
|
0x6d, 0x6f, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x61,
|
||||||
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18, 0x63, 0x6f,
|
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18, 0x63, 0x6f,
|
||||||
0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
|
0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
|
||||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd2, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd1, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||||
0x67, 0x12, 0x35, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01,
|
0x67, 0x12, 0x35, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01,
|
||||||
0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
||||||
0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52,
|
0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52,
|
||||||
0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74,
|
0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74,
|
||||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x43, 0x0a, 0x08,
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x34, 0x0a, 0x08,
|
||||||
0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28,
|
0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x18,
|
||||||
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x64, 0x6f, 0x6b, 0x6f,
|
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74,
|
||||||
0x64, 0x65, 0x6d, 0x6f, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x50, 0x6f, 0x72, 0x74,
|
0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x08, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72,
|
||||||
0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x70, 0x6f, 0x72, 0x74, 0x4d, 0x61,
|
0x6b, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x72, 0x65, 0x64,
|
||||||
0x70, 0x12, 0x34, 0x0a, 0x08, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x07, 0x20,
|
0x69, 0x72, 0x65, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x66, 0x6f, 0x6c,
|
||||||
0x03, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
|
0x6c, 0x6f, 0x77, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x75,
|
||||||
0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x08, 0x6e,
|
0x73, 0x65, 0x72, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52,
|
||||||
0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x66, 0x6f, 0x6c, 0x6c, 0x6f,
|
0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x42, 0x5b, 0x0a, 0x17, 0x63, 0x6f,
|
||||||
0x77, 0x5f, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08,
|
0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x64, 0x6f, 0x6b,
|
||||||
0x52, 0x0e, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74,
|
0x6f, 0x64, 0x65, 0x6d, 0x6f, 0x50, 0x01, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
||||||
0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x06,
|
0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f,
|
||||||
0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x1a,
|
0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x64, 0x6f, 0x6b, 0x6f, 0x64, 0x65, 0x6d,
|
||||||
0x3a, 0x0a, 0x0c, 0x50, 0x6f, 0x72, 0x74, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
|
0x6f, 0xaa, 0x02, 0x13, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x44,
|
||||||
0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
|
0x6f, 0x6b, 0x6f, 0x64, 0x65, 0x6d, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
|
||||||
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x5b, 0x0a, 0x17, 0x63,
|
|
||||||
0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x64, 0x6f,
|
|
||||||
0x6b, 0x6f, 0x64, 0x65, 0x6d, 0x6f, 0x50, 0x01, 0x5a, 0x28, 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, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x64, 0x6f, 0x6b, 0x6f, 0x64, 0x65,
|
|
||||||
0x6d, 0x6f, 0xaa, 0x02, 0x13, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e,
|
|
||||||
0x44, 0x6f, 0x6b, 0x6f, 0x64, 0x65, 0x6d, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -158,22 +142,20 @@ func file_proxy_dokodemo_config_proto_rawDescGZIP() []byte {
|
|||||||
return file_proxy_dokodemo_config_proto_rawDescData
|
return file_proxy_dokodemo_config_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_proxy_dokodemo_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
var file_proxy_dokodemo_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||||
var file_proxy_dokodemo_config_proto_goTypes = []any{
|
var file_proxy_dokodemo_config_proto_goTypes = []any{
|
||||||
(*Config)(nil), // 0: xray.proxy.dokodemo.Config
|
(*Config)(nil), // 0: xray.proxy.dokodemo.Config
|
||||||
nil, // 1: xray.proxy.dokodemo.Config.PortMapEntry
|
(*net.IPOrDomain)(nil), // 1: xray.common.net.IPOrDomain
|
||||||
(*net.IPOrDomain)(nil), // 2: xray.common.net.IPOrDomain
|
(net.Network)(0), // 2: xray.common.net.Network
|
||||||
(net.Network)(0), // 3: xray.common.net.Network
|
|
||||||
}
|
}
|
||||||
var file_proxy_dokodemo_config_proto_depIdxs = []int32{
|
var file_proxy_dokodemo_config_proto_depIdxs = []int32{
|
||||||
2, // 0: xray.proxy.dokodemo.Config.address:type_name -> xray.common.net.IPOrDomain
|
1, // 0: xray.proxy.dokodemo.Config.address:type_name -> xray.common.net.IPOrDomain
|
||||||
1, // 1: xray.proxy.dokodemo.Config.port_map:type_name -> xray.proxy.dokodemo.Config.PortMapEntry
|
2, // 1: xray.proxy.dokodemo.Config.networks:type_name -> xray.common.net.Network
|
||||||
3, // 2: xray.proxy.dokodemo.Config.networks:type_name -> xray.common.net.Network
|
2, // [2:2] is the sub-list for method output_type
|
||||||
3, // [3:3] is the sub-list for method output_type
|
2, // [2:2] is the sub-list for method input_type
|
||||||
3, // [3:3] is the sub-list for method input_type
|
2, // [2:2] is the sub-list for extension type_name
|
||||||
3, // [3:3] is the sub-list for extension type_name
|
2, // [2:2] is the sub-list for extension extendee
|
||||||
3, // [3:3] is the sub-list for extension extendee
|
0, // [0:2] is the sub-list for field type_name
|
||||||
0, // [0:3] is the sub-list for field type_name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_proxy_dokodemo_config_proto_init() }
|
func init() { file_proxy_dokodemo_config_proto_init() }
|
||||||
@@ -187,7 +169,7 @@ func file_proxy_dokodemo_config_proto_init() {
|
|||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_proxy_dokodemo_config_proto_rawDesc,
|
RawDescriptor: file_proxy_dokodemo_config_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 2,
|
NumMessages: 1,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
|
@@ -13,8 +13,6 @@ message Config {
|
|||||||
xray.common.net.IPOrDomain address = 1;
|
xray.common.net.IPOrDomain address = 1;
|
||||||
uint32 port = 2;
|
uint32 port = 2;
|
||||||
|
|
||||||
map<string, string> port_map = 3;
|
|
||||||
|
|
||||||
// List of networks that the Dokodemo accepts.
|
// List of networks that the Dokodemo accepts.
|
||||||
repeated xray.common.net.Network networks = 7;
|
repeated xray.common.net.Network networks = 7;
|
||||||
|
|
||||||
|
@@ -3,8 +3,6 @@ package dokodemo
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
@@ -38,7 +36,6 @@ type DokodemoDoor struct {
|
|||||||
config *Config
|
config *Config
|
||||||
address net.Address
|
address net.Address
|
||||||
port net.Port
|
port net.Port
|
||||||
portMap map[string]string
|
|
||||||
sockopt *session.Sockopt
|
sockopt *session.Sockopt
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +47,6 @@ func (d *DokodemoDoor) Init(config *Config, pm policy.Manager, sockopt *session.
|
|||||||
d.config = config
|
d.config = config
|
||||||
d.address = config.GetPredefinedAddress()
|
d.address = config.GetPredefinedAddress()
|
||||||
d.port = net.Port(config.Port)
|
d.port = net.Port(config.Port)
|
||||||
d.portMap = config.PortMap
|
|
||||||
d.policyManager = pm
|
d.policyManager = pm
|
||||||
d.sockopt = sockopt
|
d.sockopt = sockopt
|
||||||
|
|
||||||
@@ -77,33 +73,6 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn st
|
|||||||
Port: d.port,
|
Port: d.port,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !d.config.FollowRedirect {
|
|
||||||
host, port, err := net.SplitHostPort(conn.LocalAddr().String())
|
|
||||||
if dest.Address == nil {
|
|
||||||
if err != nil {
|
|
||||||
dest.Address = net.DomainAddress("localhost")
|
|
||||||
} else {
|
|
||||||
if strings.Contains(host, ".") {
|
|
||||||
dest.Address = net.LocalHostIP
|
|
||||||
} else {
|
|
||||||
dest.Address = net.LocalHostIPv6
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if dest.Port == 0 {
|
|
||||||
dest.Port = net.Port(common.Must2(strconv.Atoi(port)).(int))
|
|
||||||
}
|
|
||||||
if d.portMap != nil && d.portMap[port] != "" {
|
|
||||||
h, p, _ := net.SplitHostPort(d.portMap[port])
|
|
||||||
if len(h) > 0 {
|
|
||||||
dest.Address = net.ParseAddress(h)
|
|
||||||
}
|
|
||||||
if len(p) > 0 {
|
|
||||||
dest.Port = net.Port(common.Must2(strconv.Atoi(p)).(int))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
destinationOverridden := false
|
destinationOverridden := false
|
||||||
if d.config.FollowRedirect {
|
if d.config.FollowRedirect {
|
||||||
outbounds := session.OutboundsFromContext(ctx)
|
outbounds := session.OutboundsFromContext(ctx)
|
||||||
|
@@ -18,7 +18,6 @@ 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"
|
||||||
@@ -203,7 +202,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, destination)
|
writer = NewPacketWriter(conn, h, ctx, UDPOverride)
|
||||||
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{
|
||||||
@@ -239,7 +238,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, destination)
|
reader = NewPacketReader(conn, UDPOverride)
|
||||||
}
|
}
|
||||||
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)
|
||||||
@@ -274,7 +273,7 @@ func isTLSConn(conn stat.Connection) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPacketReader(conn net.Conn, UDPOverride net.Destination, DialDest net.Destination) buf.Reader {
|
func NewPacketReader(conn net.Conn, UDPOverride net.Destination) buf.Reader {
|
||||||
iConn := conn
|
iConn := conn
|
||||||
statConn, ok := iConn.(*stat.CounterConnection)
|
statConn, ok := iConn.(*stat.CounterConnection)
|
||||||
if ok {
|
if ok {
|
||||||
@@ -284,19 +283,10 @@ func NewPacketReader(conn net.Conn, UDPOverride net.Destination, DialDest net.De
|
|||||||
if statConn != nil {
|
if statConn != nil {
|
||||||
counter = statConn.ReadCounter
|
counter = statConn.ReadCounter
|
||||||
}
|
}
|
||||||
if c, ok := iConn.(*internet.PacketConnWrapper); ok {
|
if c, ok := iConn.(*internet.PacketConnWrapper); ok && UDPOverride.Address == nil && UDPOverride.Port == 0 {
|
||||||
isOverridden := false
|
|
||||||
if UDPOverride.Address != nil || UDPOverride.Port != 0 {
|
|
||||||
isOverridden = true
|
|
||||||
}
|
|
||||||
changedAddress, _, _ := net.SplitHostPort(conn.RemoteAddr().String())
|
|
||||||
|
|
||||||
return &PacketReader{
|
return &PacketReader{
|
||||||
PacketConnWrapper: c,
|
PacketConnWrapper: c,
|
||||||
Counter: counter,
|
Counter: counter,
|
||||||
IsOverridden: isOverridden,
|
|
||||||
InitUnchangedAddr: DialDest.Address,
|
|
||||||
InitChangedAddr: net.ParseAddress(changedAddress),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &buf.PacketReader{Reader: conn}
|
return &buf.PacketReader{Reader: conn}
|
||||||
@@ -305,9 +295,6 @@ func NewPacketReader(conn net.Conn, UDPOverride net.Destination, DialDest net.De
|
|||||||
type PacketReader struct {
|
type PacketReader struct {
|
||||||
*internet.PacketConnWrapper
|
*internet.PacketConnWrapper
|
||||||
stats.Counter
|
stats.Counter
|
||||||
IsOverridden bool
|
|
||||||
InitUnchangedAddr net.Address
|
|
||||||
InitChangedAddr net.Address
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
||||||
@@ -319,27 +306,18 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
b.Resize(0, int32(n))
|
b.Resize(0, int32(n))
|
||||||
// if udp dest addr is changed, we are unable to get the correct src addr
|
|
||||||
// so we don't attach src info to udp packet, break cone behavior, assuming the dial dest is the expected scr addr
|
|
||||||
if !r.IsOverridden {
|
|
||||||
address := net.IPAddress(d.(*net.UDPAddr).IP)
|
|
||||||
if r.InitChangedAddr == address {
|
|
||||||
address = r.InitUnchangedAddr
|
|
||||||
}
|
|
||||||
b.UDP = &net.Destination{
|
b.UDP = &net.Destination{
|
||||||
Address: address,
|
Address: net.IPAddress(d.(*net.UDPAddr).IP),
|
||||||
Port: net.Port(d.(*net.UDPAddr).Port),
|
Port: net.Port(d.(*net.UDPAddr).Port),
|
||||||
Network: net.Network_UDP,
|
Network: net.Network_UDP,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if r.Counter != nil {
|
if r.Counter != nil {
|
||||||
r.Counter.Add(int64(n))
|
r.Counter.Add(int64(n))
|
||||||
}
|
}
|
||||||
return buf.MultiBuffer{b}, nil
|
return buf.MultiBuffer{b}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) buf.Writer {
|
||||||
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 {
|
||||||
@@ -350,20 +328,12 @@ 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,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -376,12 +346,6 @@ 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 {
|
||||||
@@ -400,34 +364,10 @@ 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 b.UDP.Address.Family().IsDomain() {
|
if w.Handler.config.hasStrategy() && b.UDP.Address.Family().IsDomain() {
|
||||||
if ip, ok := w.resolvedUDPAddr.Load(b.UDP.Address.Domain()); ok {
|
ip := w.Handler.resolveIP(w.Context, b.UDP.Address.Domain(), nil)
|
||||||
|
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,7 +128,6 @@ 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,15 +245,13 @@ 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,7 +259,6 @@ 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,10 +206,7 @@ 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, errR := first.ReadFrom(connection)
|
firstLen, _ := first.ReadFrom(connection)
|
||||||
if errR != nil {
|
|
||||||
return errR
|
|
||||||
}
|
|
||||||
errors.LogInfo(ctx, "firstLen = ", firstLen)
|
errors.LogInfo(ctx, "firstLen = ", firstLen)
|
||||||
|
|
||||||
reader := &buf.BufferedReader{
|
reader := &buf.BufferedReader{
|
||||||
|
@@ -273,11 +273,6 @@ func (h *Handler) createIPCRequest() string {
|
|||||||
|
|
||||||
request.WriteString(fmt.Sprintf("private_key=%s\n", h.conf.SecretKey))
|
request.WriteString(fmt.Sprintf("private_key=%s\n", h.conf.SecretKey))
|
||||||
|
|
||||||
if !h.conf.IsClient {
|
|
||||||
// placeholder, we'll handle actual port listening on Xray
|
|
||||||
request.WriteString("listen_port=1337\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, peer := range h.conf.Peers {
|
for _, peer := range h.conf.Peers {
|
||||||
if peer.PublicKey != "" {
|
if peer.PublicKey != "" {
|
||||||
request.WriteString(fmt.Sprintf("public_key=%s\n", peer.PublicKey))
|
request.WriteString(fmt.Sprintf("public_key=%s\n", peer.PublicKey))
|
||||||
|
@@ -31,11 +31,6 @@ func (c *DeviceConfig) fallbackIP6() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *DeviceConfig) createTun() tunCreator {
|
func (c *DeviceConfig) createTun() tunCreator {
|
||||||
if !c.IsClient {
|
|
||||||
// See tun_linux.go createKernelTun()
|
|
||||||
errors.LogWarning(context.Background(), "Using gVisor TUN. WG inbound doesn't support kernel TUN yet.")
|
|
||||||
return createGVisorTun
|
|
||||||
}
|
|
||||||
if c.NoKernelTun {
|
if c.NoKernelTun {
|
||||||
errors.LogWarning(context.Background(), "Using gVisor TUN. NoKernelTun is set to true.")
|
errors.LogWarning(context.Background(), "Using gVisor TUN. NoKernelTun is set to true.")
|
||||||
return createGVisorTun
|
return createGVisorTun
|
||||||
|
@@ -1,194 +0,0 @@
|
|||||||
package wireguard
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
goerrors "errors"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
|
||||||
"github.com/xtls/xray-core/common/buf"
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/log"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/common/session"
|
|
||||||
"github.com/xtls/xray-core/common/signal"
|
|
||||||
"github.com/xtls/xray-core/common/task"
|
|
||||||
"github.com/xtls/xray-core/core"
|
|
||||||
"github.com/xtls/xray-core/features/dns"
|
|
||||||
"github.com/xtls/xray-core/features/policy"
|
|
||||||
"github.com/xtls/xray-core/features/routing"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/stat"
|
|
||||||
)
|
|
||||||
|
|
||||||
var nullDestination = net.TCPDestination(net.AnyIP, 0)
|
|
||||||
|
|
||||||
type Server struct {
|
|
||||||
bindServer *netBindServer
|
|
||||||
|
|
||||||
info routingInfo
|
|
||||||
policyManager policy.Manager
|
|
||||||
}
|
|
||||||
|
|
||||||
type routingInfo struct {
|
|
||||||
ctx context.Context
|
|
||||||
dispatcher routing.Dispatcher
|
|
||||||
inboundTag *session.Inbound
|
|
||||||
outboundTag *session.Outbound
|
|
||||||
contentTag *session.Content
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewServer(ctx context.Context, conf *DeviceConfig) (*Server, error) {
|
|
||||||
v := core.MustFromContext(ctx)
|
|
||||||
|
|
||||||
endpoints, hasIPv4, hasIPv6, err := parseEndpoints(conf)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
server := &Server{
|
|
||||||
bindServer: &netBindServer{
|
|
||||||
netBind: netBind{
|
|
||||||
dns: v.GetFeature(dns.ClientType()).(dns.Client),
|
|
||||||
dnsOption: dns.IPOption{
|
|
||||||
IPv4Enable: hasIPv4,
|
|
||||||
IPv6Enable: hasIPv6,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
|
|
||||||
}
|
|
||||||
|
|
||||||
tun, err := conf.createTun()(endpoints, int(conf.Mtu), server.forwardConnection)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = tun.BuildDevice(createIPCRequest(conf), server.bindServer); err != nil {
|
|
||||||
_ = tun.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return server, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Network implements proxy.Inbound.
|
|
||||||
func (*Server) Network() []net.Network {
|
|
||||||
return []net.Network{net.Network_UDP}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process implements proxy.Inbound.
|
|
||||||
func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Connection, dispatcher routing.Dispatcher) error {
|
|
||||||
inbound := session.InboundFromContext(ctx)
|
|
||||||
inbound.Name = "wireguard"
|
|
||||||
inbound.CanSpliceCopy = 3
|
|
||||||
outbounds := session.OutboundsFromContext(ctx)
|
|
||||||
ob := outbounds[len(outbounds)-1]
|
|
||||||
|
|
||||||
s.info = routingInfo{
|
|
||||||
ctx: core.ToBackgroundDetachedContext(ctx),
|
|
||||||
dispatcher: dispatcher,
|
|
||||||
inboundTag: session.InboundFromContext(ctx),
|
|
||||||
outboundTag: ob,
|
|
||||||
contentTag: session.ContentFromContext(ctx),
|
|
||||||
}
|
|
||||||
|
|
||||||
ep, err := s.bindServer.ParseEndpoint(conn.RemoteAddr().String())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
nep := ep.(*netEndpoint)
|
|
||||||
nep.conn = conn
|
|
||||||
|
|
||||||
reader := buf.NewPacketReader(conn)
|
|
||||||
for {
|
|
||||||
mpayload, err := reader.ReadMultiBuffer()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, payload := range mpayload {
|
|
||||||
v, ok := <-s.bindServer.readQueue
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
i, err := payload.Read(v.buff)
|
|
||||||
|
|
||||||
v.bytes = i
|
|
||||||
v.endpoint = nep
|
|
||||||
v.err = err
|
|
||||||
v.waiter.Done()
|
|
||||||
if err != nil && goerrors.Is(err, io.EOF) {
|
|
||||||
nep.conn = nil
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) forwardConnection(dest net.Destination, conn net.Conn) {
|
|
||||||
if s.info.dispatcher == nil {
|
|
||||||
errors.LogError(s.info.ctx, "unexpected: dispatcher == nil")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(core.ToBackgroundDetachedContext(s.info.ctx))
|
|
||||||
plcy := s.policyManager.ForLevel(0)
|
|
||||||
timer := signal.CancelAfterInactivity(ctx, cancel, plcy.Timeouts.ConnectionIdle)
|
|
||||||
|
|
||||||
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
|
|
||||||
From: nullDestination,
|
|
||||||
To: dest,
|
|
||||||
Status: log.AccessAccepted,
|
|
||||||
Reason: "",
|
|
||||||
})
|
|
||||||
|
|
||||||
if s.info.inboundTag != nil {
|
|
||||||
ctx = session.ContextWithInbound(ctx, s.info.inboundTag)
|
|
||||||
}
|
|
||||||
|
|
||||||
// what's this?
|
|
||||||
// Session information should not be shared between different connections
|
|
||||||
// why reuse them in server level? This will cause incorrect destoverride and unexpected routing behavior.
|
|
||||||
// Disable it temporarily. Maybe s.info should be removed.
|
|
||||||
|
|
||||||
// if s.info.outboundTag != nil {
|
|
||||||
// ctx = session.ContextWithOutbounds(ctx, []*session.Outbound{s.info.outboundTag})
|
|
||||||
// }
|
|
||||||
// if s.info.contentTag != nil {
|
|
||||||
// ctx = session.ContextWithContent(ctx, s.info.contentTag)
|
|
||||||
// }
|
|
||||||
|
|
||||||
link, err := s.info.dispatcher.Dispatch(ctx, dest)
|
|
||||||
if err != nil {
|
|
||||||
errors.LogErrorInner(s.info.ctx, err, "dispatch connection")
|
|
||||||
}
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
requestDone := func() error {
|
|
||||||
defer timer.SetTimeout(plcy.Timeouts.DownlinkOnly)
|
|
||||||
if err := buf.Copy(buf.NewReader(conn), link.Writer, buf.UpdateActivity(timer)); err != nil {
|
|
||||||
return errors.New("failed to transport all TCP request").Base(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
responseDone := func() error {
|
|
||||||
defer timer.SetTimeout(plcy.Timeouts.UplinkOnly)
|
|
||||||
if err := buf.Copy(link.Reader, buf.NewWriter(conn), buf.UpdateActivity(timer)); err != nil {
|
|
||||||
return errors.New("failed to transport all TCP response").Base(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
requestDonePost := task.OnSuccess(requestDone, task.Close(link.Writer))
|
|
||||||
if err := task.Run(ctx, requestDonePost, responseDone); err != nil {
|
|
||||||
common.Interrupt(link.Reader)
|
|
||||||
common.Interrupt(link.Writer)
|
|
||||||
errors.LogDebugInner(s.info.ctx, err, "connection ends")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,52 +0,0 @@
|
|||||||
package wireguard_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"runtime/debug"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/core"
|
|
||||||
"github.com/xtls/xray-core/proxy/wireguard"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TestWireGuardServerInitializationError verifies that an error during TUN initialization
|
|
||||||
// (triggered by an empty SecretKey) in the WireGuard server does not cause a panic and returns an error instead.
|
|
||||||
func TestWireGuardServerInitializationError(t *testing.T) {
|
|
||||||
// Create a minimal core instance with default features
|
|
||||||
config := &core.Config{}
|
|
||||||
instance, err := core.New(config)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to create core instance: %v", err)
|
|
||||||
}
|
|
||||||
// Set the Xray instance in the context
|
|
||||||
ctx := context.WithValue(context.Background(), core.XrayKey(1), instance)
|
|
||||||
|
|
||||||
// Define the server configuration with an empty SecretKey to trigger error
|
|
||||||
conf := &wireguard.DeviceConfig{
|
|
||||||
IsClient: false,
|
|
||||||
Endpoint: []string{"10.0.0.1/32"},
|
|
||||||
Mtu: 1420,
|
|
||||||
SecretKey: "", // Empty SecretKey to trigger error
|
|
||||||
Peers: []*wireguard.PeerConfig{
|
|
||||||
{
|
|
||||||
PublicKey: "some_public_key",
|
|
||||||
AllowedIps: []string{"10.0.0.2/32"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use defer to catch any panic and fail the test explicitly
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
t.Errorf("TUN initialization panicked: %v", r)
|
|
||||||
debug.PrintStack()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Attempt to initialize the WireGuard server
|
|
||||||
_, err = wireguard.NewServer(ctx, conf)
|
|
||||||
|
|
||||||
// Check that an error is returned
|
|
||||||
assert.ErrorContains(t, err, "failed to set private_key: hex string does not fit the slice")
|
|
||||||
}
|
|
@@ -30,11 +30,7 @@ var wgLogger = &device.Logger{
|
|||||||
func init() {
|
func init() {
|
||||||
common.Must(common.RegisterConfig((*DeviceConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
common.Must(common.RegisterConfig((*DeviceConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||||
deviceConfig := config.(*DeviceConfig)
|
deviceConfig := config.(*DeviceConfig)
|
||||||
if deviceConfig.IsClient {
|
|
||||||
return New(ctx, deviceConfig)
|
return New(ctx, deviceConfig)
|
||||||
} else {
|
|
||||||
return NewServer(ctx, deviceConfig)
|
|
||||||
}
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,39 +68,3 @@ func parseEndpoints(conf *DeviceConfig) ([]netip.Addr, bool, bool, error) {
|
|||||||
|
|
||||||
return endpoints, hasIPv4, hasIPv6, nil
|
return endpoints, hasIPv4, hasIPv6, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// serialize the config into an IPC request
|
|
||||||
func createIPCRequest(conf *DeviceConfig) string {
|
|
||||||
var request strings.Builder
|
|
||||||
|
|
||||||
request.WriteString(fmt.Sprintf("private_key=%s\n", conf.SecretKey))
|
|
||||||
|
|
||||||
if !conf.IsClient {
|
|
||||||
// placeholder, we'll handle actual port listening on Xray
|
|
||||||
request.WriteString("listen_port=1337\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, peer := range conf.Peers {
|
|
||||||
if peer.PublicKey != "" {
|
|
||||||
request.WriteString(fmt.Sprintf("public_key=%s\n", peer.PublicKey))
|
|
||||||
}
|
|
||||||
|
|
||||||
if peer.PreSharedKey != "" {
|
|
||||||
request.WriteString(fmt.Sprintf("preshared_key=%s\n", peer.PreSharedKey))
|
|
||||||
}
|
|
||||||
|
|
||||||
if peer.Endpoint != "" {
|
|
||||||
request.WriteString(fmt.Sprintf("endpoint=%s\n", peer.Endpoint))
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ip := range peer.AllowedIps {
|
|
||||||
request.WriteString(fmt.Sprintf("allowed_ip=%s\n", ip))
|
|
||||||
}
|
|
||||||
|
|
||||||
if peer.KeepAlive != 0 {
|
|
||||||
request.WriteString(fmt.Sprintf("persistent_keepalive_interval=%d\n", peer.KeepAlive))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return request.String()[:request.Len()]
|
|
||||||
}
|
|
||||||
|
@@ -13,10 +13,8 @@ import (
|
|||||||
core "github.com/xtls/xray-core/core"
|
core "github.com/xtls/xray-core/core"
|
||||||
"github.com/xtls/xray-core/infra/conf"
|
"github.com/xtls/xray-core/infra/conf"
|
||||||
"github.com/xtls/xray-core/proxy/dokodemo"
|
"github.com/xtls/xray-core/proxy/dokodemo"
|
||||||
"github.com/xtls/xray-core/proxy/freedom"
|
|
||||||
"github.com/xtls/xray-core/proxy/wireguard"
|
"github.com/xtls/xray-core/proxy/wireguard"
|
||||||
"github.com/xtls/xray-core/testing/servers/tcp"
|
"github.com/xtls/xray-core/testing/servers/tcp"
|
||||||
"github.com/xtls/xray-core/testing/servers/udp"
|
|
||||||
//"golang.org/x/sync/errgroup"
|
//"golang.org/x/sync/errgroup"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,45 +26,9 @@ func TestWireguard(t *testing.T) {
|
|||||||
common.Must(err)
|
common.Must(err)
|
||||||
defer tcpServer.Close()
|
defer tcpServer.Close()
|
||||||
|
|
||||||
serverPrivate, _ := conf.ParseWireGuardKey("EGs4lTSJPmgELx6YiJAmPR2meWi6bY+e9rTdCipSj10=")
|
|
||||||
serverPublic, _ := conf.ParseWireGuardKey("osAMIyil18HeZXGGBDC9KpZoM+L2iGyXWVSYivuM9B0=")
|
|
||||||
clientPrivate, _ := conf.ParseWireGuardKey("CPQSpgxgdQRZa5SUbT3HLv+mmDVHLW5YR/rQlzum/2I=")
|
clientPrivate, _ := conf.ParseWireGuardKey("CPQSpgxgdQRZa5SUbT3HLv+mmDVHLW5YR/rQlzum/2I=")
|
||||||
clientPublic, _ := conf.ParseWireGuardKey("MmLJ5iHFVVBp7VsB0hxfpQ0wEzAbT2KQnpQpj0+RtBw=")
|
clientPublic, _ := conf.ParseWireGuardKey("MmLJ5iHFVVBp7VsB0hxfpQ0wEzAbT2KQnpQpj0+RtBw=")
|
||||||
|
|
||||||
serverPort := udp.PickPort()
|
|
||||||
serverConfig := &core.Config{
|
|
||||||
App: []*serial.TypedMessage{
|
|
||||||
serial.ToTypedMessage(&log.Config{
|
|
||||||
ErrorLogLevel: clog.Severity_Debug,
|
|
||||||
ErrorLogType: log.LogType_Console,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
Inbound: []*core.InboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
|
||||||
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
|
|
||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
|
||||||
}),
|
|
||||||
ProxySettings: serial.ToTypedMessage(&wireguard.DeviceConfig{
|
|
||||||
IsClient: false,
|
|
||||||
NoKernelTun: false,
|
|
||||||
Endpoint: []string{"10.0.0.1"},
|
|
||||||
Mtu: 1420,
|
|
||||||
SecretKey: serverPrivate,
|
|
||||||
Peers: []*wireguard.PeerConfig{{
|
|
||||||
PublicKey: serverPublic,
|
|
||||||
AllowedIps: []string{"0.0.0.0/0", "::0/0"},
|
|
||||||
}},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
clientPort := tcp.PickPort()
|
clientPort := tcp.PickPort()
|
||||||
clientConfig := &core.Config{
|
clientConfig := &core.Config{
|
||||||
App: []*serial.TypedMessage{
|
App: []*serial.TypedMessage{
|
||||||
@@ -91,13 +53,12 @@ func TestWireguard(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&wireguard.DeviceConfig{
|
ProxySettings: serial.ToTypedMessage(&wireguard.DeviceConfig{
|
||||||
IsClient: true,
|
|
||||||
NoKernelTun: false,
|
NoKernelTun: false,
|
||||||
Endpoint: []string{"10.0.0.2"},
|
Endpoint: []string{"10.0.0.2"},
|
||||||
Mtu: 1420,
|
Mtu: 1420,
|
||||||
SecretKey: clientPrivate,
|
SecretKey: clientPrivate,
|
||||||
Peers: []*wireguard.PeerConfig{{
|
Peers: []*wireguard.PeerConfig{{
|
||||||
Endpoint: "127.0.0.1:" + serverPort.String(),
|
Endpoint: "127.0.0.1:12777",
|
||||||
PublicKey: clientPublic,
|
PublicKey: clientPublic,
|
||||||
AllowedIps: []string{"0.0.0.0/0", "::0/0"},
|
AllowedIps: []string{"0.0.0.0/0", "::0/0"},
|
||||||
}},
|
}},
|
||||||
@@ -106,7 +67,7 @@ func TestWireguard(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
servers, err := InitializeServerConfigs(serverConfig, clientConfig)
|
servers, err := InitializeServerConfigs(clientConfig)
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
defer CloseAllServers(servers)
|
defer CloseAllServers(servers)
|
||||||
|
|
||||||
|
@@ -7,7 +7,6 @@ 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"
|
||||||
@@ -33,10 +32,6 @@ 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.28.2
|
// protoc v5.29.4
|
||||||
// source: transport/internet/reality/config.proto
|
// source: transport/internet/reality/config.proto
|
||||||
|
|
||||||
package reality
|
package reality
|
||||||
@@ -35,17 +35,15 @@ 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"`
|
||||||
Mldsa65Verify []byte `protobuf:"bytes,25,opt,name=mldsa65_verify,json=mldsa65Verify,proto3" json:"mldsa65_verify,omitempty"`
|
SpiderX string `protobuf:"bytes,25,opt,name=spider_x,json=spiderX,proto3" json:"spider_x,omitempty"`
|
||||||
SpiderX string `protobuf:"bytes,26,opt,name=spider_x,json=spiderX,proto3" json:"spider_x,omitempty"`
|
SpiderY []int64 `protobuf:"varint,26,rep,packed,name=spider_y,json=spiderY,proto3" json:"spider_y,omitempty"`
|
||||||
SpiderY []int64 `protobuf:"varint,27,rep,packed,name=spider_y,json=spiderY,proto3" json:"spider_y,omitempty"`
|
MasterKeyLog string `protobuf:"bytes,27,opt,name=master_key_log,json=masterKeyLog,proto3" json:"master_key_log,omitempty"`
|
||||||
MasterKeyLog string `protobuf:"bytes,31,opt,name=master_key_log,json=masterKeyLog,proto3" json:"master_key_log,omitempty"`
|
LimitFallbackUpload *LimitFallback `protobuf:"bytes,28,opt,name=limit_fallback_upload,json=limitFallbackUpload,proto3" json:"limit_fallback_upload,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() {
|
||||||
@@ -148,27 +146,6 @@ 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
|
||||||
@@ -197,13 +174,6 @@ 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
|
||||||
@@ -225,6 +195,20 @@ 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
|
||||||
@@ -293,7 +277,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, 0x98, 0x06, 0x0a, 0x06, 0x43,
|
0x65, 0x74, 0x2e, 0x72, 0x65, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x22, 0xce, 0x05, 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,
|
||||||
@@ -312,55 +296,50 @@ 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, 0x21, 0x0a, 0x0c, 0x6d, 0x6c, 0x64, 0x73, 0x61, 0x36,
|
0x6f, 0x72, 0x74, 0x49, 0x64, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72,
|
||||||
0x35, 0x5f, 0x73, 0x65, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x6d, 0x6c,
|
0x70, 0x72, 0x69, 0x6e, 0x74, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x46, 0x69, 0x6e,
|
||||||
0x64, 0x73, 0x61, 0x36, 0x35, 0x53, 0x65, 0x65, 0x64, 0x12, 0x62, 0x0a, 0x15, 0x6c, 0x69, 0x6d,
|
0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76,
|
||||||
0x69, 0x74, 0x5f, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x75, 0x70, 0x6c, 0x6f,
|
0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73,
|
||||||
0x61, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62,
|
||||||
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
|
0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70,
|
||||||
0x65, 0x74, 0x2e, 0x72, 0x65, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x2e, 0x4c, 0x69, 0x6d, 0x69, 0x74,
|
0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x68, 0x6f, 0x72,
|
||||||
0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x13, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x46,
|
0x74, 0x5f, 0x69, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x73, 0x68, 0x6f, 0x72,
|
||||||
0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x66, 0x0a,
|
0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x78, 0x18,
|
||||||
0x17, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f,
|
0x19, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x69, 0x64, 0x65, 0x72, 0x58, 0x12, 0x19,
|
||||||
0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e,
|
0x0a, 0x08, 0x73, 0x70, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x79, 0x18, 0x1a, 0x20, 0x03, 0x28, 0x03,
|
||||||
|
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, 0x15,
|
0x2e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x13,
|
||||||
0x6c, 0x69, 0x6d, 0x69, 0x74, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x44, 0x6f, 0x77,
|
0x6c, 0x69, 0x6d, 0x69, 0x74, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x55, 0x70, 0x6c,
|
||||||
0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70,
|
0x6f, 0x61, 0x64, 0x12, 0x66, 0x0a, 0x17, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x66, 0x61, 0x6c,
|
||||||
0x72, 0x69, 0x6e, 0x74, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x46, 0x69, 0x6e, 0x67,
|
0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x1d,
|
||||||
0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65,
|
0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e,
|
||||||
0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65,
|
0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x72,
|
||||||
0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c,
|
0x65, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x2e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x46, 0x61, 0x6c, 0x6c,
|
||||||
0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75,
|
0x62, 0x61, 0x63, 0x6b, 0x52, 0x15, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x46, 0x61, 0x6c, 0x6c, 0x62,
|
||||||
0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x68, 0x6f, 0x72, 0x74,
|
0x61, 0x63, 0x6b, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x83, 0x01, 0x0a, 0x0d,
|
||||||
0x5f, 0x69, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x73, 0x68, 0x6f, 0x72, 0x74,
|
0x4c, 0x69, 0x6d, 0x69, 0x74, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x1f, 0x0a,
|
||||||
0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x6c, 0x64, 0x73, 0x61, 0x36, 0x35, 0x5f, 0x76, 0x65,
|
0x0b, 0x61, 0x66, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01,
|
||||||
0x72, 0x69, 0x66, 0x79, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x6d, 0x6c, 0x64, 0x73,
|
0x28, 0x04, 0x52, 0x0a, 0x61, 0x66, 0x74, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x22,
|
||||||
0x61, 0x36, 0x35, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x69,
|
0x0a, 0x0d, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x18,
|
||||||
0x64, 0x65, 0x72, 0x5f, 0x78, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x69,
|
0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, 0x50, 0x65, 0x72, 0x53,
|
||||||
0x64, 0x65, 0x72, 0x58, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x79,
|
0x65, 0x63, 0x12, 0x2d, 0x0a, 0x13, 0x62, 0x75, 0x72, 0x73, 0x74, 0x5f, 0x62, 0x79, 0x74, 0x65,
|
||||||
0x18, 0x1b, 0x20, 0x03, 0x28, 0x03, 0x52, 0x07, 0x73, 0x70, 0x69, 0x64, 0x65, 0x72, 0x59, 0x12,
|
0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52,
|
||||||
0x24, 0x0a, 0x0e, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x6c, 0x6f,
|
0x10, 0x62, 0x75, 0x72, 0x73, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x50, 0x65, 0x72, 0x53, 0x65,
|
||||||
0x67, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b,
|
0x63, 0x42, 0x7f, 0x0a, 0x23, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72,
|
||||||
0x65, 0x79, 0x4c, 0x6f, 0x67, 0x22, 0x83, 0x01, 0x0a, 0x0d, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x46,
|
0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
|
||||||
0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x66, 0x74, 0x65, 0x72,
|
0x2e, 0x72, 0x65, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x01, 0x5a, 0x34, 0x67, 0x69, 0x74, 0x68,
|
||||||
0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x61, 0x66,
|
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79,
|
||||||
0x74, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x62, 0x79, 0x74, 0x65,
|
0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f,
|
||||||
0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52,
|
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x69, 0x74, 0x79,
|
||||||
0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x12, 0x2d, 0x0a, 0x13,
|
0xaa, 0x02, 0x1f, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
|
||||||
0x62, 0x75, 0x72, 0x73, 0x74, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f,
|
0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x52, 0x65, 0x61, 0x6c, 0x69,
|
||||||
0x73, 0x65, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x62, 0x75, 0x72, 0x73, 0x74,
|
0x74, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
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,19 +18,16 @@ 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;
|
||||||
bytes mldsa65_verify = 25;
|
string spider_x = 25;
|
||||||
string spider_x = 26;
|
repeated int64 spider_y = 26;
|
||||||
repeated int64 spider_y = 27;
|
string master_key_log = 27;
|
||||||
|
|
||||||
string master_key_log = 31;
|
LimitFallback limit_fallback_upload = 28;
|
||||||
|
LimitFallback limit_fallback_download = 29;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LimitFallback {
|
message LimitFallback {
|
||||||
|
@@ -23,7 +23,6 @@ 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"
|
||||||
@@ -57,7 +56,6 @@ 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
|
||||||
@@ -75,34 +73,16 @@ 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) {
|
||||||
if len(c.Config.Mldsa65Verify) > 0 {
|
|
||||||
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
|
c.Verified = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
c.Verified = true
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
opts := x509.VerifyOptions{
|
opts := x509.VerifyOptions{
|
||||||
DNSName: c.ServerName,
|
DNSName: c.ServerName,
|
||||||
Intermediates: x509.NewCertPool(),
|
Intermediates: x509.NewCertPool(),
|
||||||
@@ -118,9 +98,7 @@ 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,
|
||||||
@@ -149,20 +127,16 @@ 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 {
|
||||||
fmt.Printf("REALITY localAddr: %v\thello.SessionId[:16]: %v\n", localAddr, hello.SessionId[:16])
|
errors.LogInfo(ctx, fmt.Sprintf("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")
|
||||||
}
|
}
|
||||||
ecdhe := uConn.HandshakeState.State13.KeyShareKeys.Ecdhe
|
if uConn.HandshakeState.State13.KeyShareKeys.Ecdhe == nil {
|
||||||
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, _ = ecdhe.ECDH(publicKey)
|
uConn.AuthKey, _ = uConn.HandshakeState.State13.KeyShareKeys.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")
|
||||||
}
|
}
|
||||||
@@ -172,7 +146,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 {
|
||||||
fmt.Printf("REALITY localAddr: %v\tuConn.AuthKey[:16]: %v\tAEAD: %T\n", localAddr, uConn.AuthKey[:16], aead)
|
errors.LogInfo(ctx, fmt.Sprintf("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)
|
||||||
@@ -181,14 +155,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 {
|
||||||
fmt.Printf("REALITY localAddr: %v\tuConn.Verified: %v\n", localAddr, uConn.Verified)
|
errors.LogInfo(ctx, fmt.Sprintf("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) {
|
||||||
fmt.Printf("REALITY localAddr: %v\tDialTLSContext\n", localAddr)
|
errors.LogInfo(ctx, fmt.Sprintf("REALITY localAddr: %v\tDialTLSContext\n", localAddr))
|
||||||
return uConn, nil
|
return uConn, nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -225,7 +199,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 {
|
||||||
fmt.Printf("REALITY localAddr: %v\treq.UserAgent(): %v\n", localAddr, req.UserAgent())
|
errors.LogInfo(ctx, fmt.Sprintf("REALITY localAddr: %v\treq.UserAgent(): %v\n", localAddr, req.UserAgent()))
|
||||||
}
|
}
|
||||||
times := 1
|
times := 1
|
||||||
if !first {
|
if !first {
|
||||||
@@ -253,9 +227,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 {
|
||||||
fmt.Printf("REALITY localAddr: %v\treq.Referer(): %v\n", localAddr, req.Referer())
|
errors.LogInfo(ctx, fmt.Sprintf("REALITY localAddr: %v\treq.Referer(): %v\n", localAddr, req.Referer()))
|
||||||
fmt.Printf("REALITY localAddr: %v\tlen(body): %v\n", localAddr, len(body))
|
errors.LogInfo(ctx, fmt.Sprintf("REALITY localAddr: %v\tlen(body): %v\n", localAddr, len(body)))
|
||||||
fmt.Printf("REALITY localAddr: %v\tlen(paths): %v\n", localAddr, len(paths))
|
errors.LogInfo(ctx, fmt.Sprintf("REALITY localAddr: %v\tlen(paths): %v\n", localAddr, len(paths)))
|
||||||
}
|
}
|
||||||
maps.Unlock()
|
maps.Unlock()
|
||||||
if !first {
|
if !first {
|
||||||
|
@@ -64,6 +64,26 @@ 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,7 +3,6 @@ package internet
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
gonet "net"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -88,34 +87,14 @@ func (d *DefaultSystemDialer) Dial(ctx context.Context, src net.Address, dest ne
|
|||||||
Dest: destAddr,
|
Dest: destAddr,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
// Chrome defaults
|
goStdKeepAlive := time.Duration(0)
|
||||||
keepAliveConfig := gonet.KeepAliveConfig{
|
if sockopt != nil && (sockopt.TcpKeepAliveInterval != 0 || sockopt.TcpKeepAliveIdle != 0) {
|
||||||
Enable: true,
|
goStdKeepAlive = time.Duration(-1)
|
||||||
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: keepAlive,
|
KeepAlive: goStdKeepAlive,
|
||||||
KeepAliveConfig: keepAliveConfig,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if sockopt != nil || len(d.controllers) > 0 {
|
if sockopt != nil || len(d.controllers) > 0 {
|
||||||
|
@@ -2,7 +2,6 @@ package internet
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
gonet "net"
|
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -89,25 +88,9 @@ 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.TcpKeepAliveIdle*sockopt.TcpKeepAliveInterval < 0 {
|
if sockopt.TcpKeepAliveInterval != 0 || sockopt.TcpKeepAliveIdle != 0 {
|
||||||
return nil, errors.New("invalid TcpKeepAliveIdle or TcpKeepAliveInterval value: ", sockopt.TcpKeepAliveIdle, " ", sockopt.TcpKeepAliveInterval)
|
lc.KeepAlive = time.Duration(-1)
|
||||||
}
|
|
||||||
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)
|
||||||
|
@@ -2,7 +2,6 @@ package tcp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
gotls "crypto/tls"
|
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -16,6 +15,10 @@ import (
|
|||||||
"github.com/xtls/xray-core/transport/internet/tls"
|
"github.com/xtls/xray-core/transport/internet/tls"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func IsFromMitm(str string) bool {
|
||||||
|
return strings.ToLower(str) == "frommitm"
|
||||||
|
}
|
||||||
|
|
||||||
// Dial dials a new TCP connection to the given destination.
|
// Dial dials a new TCP connection to the given destination.
|
||||||
func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (stat.Connection, error) {
|
func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (stat.Connection, error) {
|
||||||
errors.LogInfo(ctx, "dialing TCP to ", dest)
|
errors.LogInfo(ctx, "dialing TCP to ", dest)
|
||||||
@@ -27,17 +30,14 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
|
|||||||
if config := tls.ConfigFromStreamSettings(streamSettings); config != nil {
|
if config := tls.ConfigFromStreamSettings(streamSettings); config != nil {
|
||||||
mitmServerName := session.MitmServerNameFromContext(ctx)
|
mitmServerName := session.MitmServerNameFromContext(ctx)
|
||||||
mitmAlpn11 := session.MitmAlpn11FromContext(ctx)
|
mitmAlpn11 := session.MitmAlpn11FromContext(ctx)
|
||||||
var tlsConfig *gotls.Config
|
tlsConfig := config.GetTLSConfig(tls.WithDestination(dest))
|
||||||
if tls.IsFromMitm(config.ServerName) {
|
if IsFromMitm(tlsConfig.ServerName) {
|
||||||
tlsConfig = config.GetTLSConfig(tls.WithOverrideName(mitmServerName))
|
tlsConfig.ServerName = mitmServerName
|
||||||
} else {
|
|
||||||
tlsConfig = config.GetTLSConfig(tls.WithDestination(dest))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isFromMitmVerify := false
|
isFromMitmVerify := false
|
||||||
if r, ok := tlsConfig.Rand.(*tls.RandCarrier); ok && len(r.VerifyPeerCertInNames) > 0 {
|
if r, ok := tlsConfig.Rand.(*tls.RandCarrier); ok && len(r.VerifyPeerCertInNames) > 0 {
|
||||||
for i, name := range r.VerifyPeerCertInNames {
|
for i, name := range r.VerifyPeerCertInNames {
|
||||||
if tls.IsFromMitm(name) {
|
if IsFromMitm(name) {
|
||||||
isFromMitmVerify = true
|
isFromMitmVerify = true
|
||||||
r.VerifyPeerCertInNames[0], r.VerifyPeerCertInNames[i] = r.VerifyPeerCertInNames[i], r.VerifyPeerCertInNames[0]
|
r.VerifyPeerCertInNames[0], r.VerifyPeerCertInNames[i] = r.VerifyPeerCertInNames[i], r.VerifyPeerCertInNames[0]
|
||||||
r.VerifyPeerCertInNames = r.VerifyPeerCertInNames[1:]
|
r.VerifyPeerCertInNames = r.VerifyPeerCertInNames[1:]
|
||||||
@@ -56,7 +56,7 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isFromMitmAlpn := len(tlsConfig.NextProtos) == 1 && tls.IsFromMitm(tlsConfig.NextProtos[0])
|
isFromMitmAlpn := len(tlsConfig.NextProtos) == 1 && IsFromMitm(tlsConfig.NextProtos[0])
|
||||||
if isFromMitmAlpn {
|
if isFromMitmAlpn {
|
||||||
if mitmAlpn11 {
|
if mitmAlpn11 {
|
||||||
tlsConfig.NextProtos[0] = "http/1.1"
|
tlsConfig.NextProtos[0] = "http/1.1"
|
||||||
|
@@ -8,7 +8,6 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"github.com/xtls/xray-core/features/dns"
|
|
||||||
"os"
|
"os"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -276,9 +275,6 @@ func getNewGetCertificateFunc(certs []*tls.Certificate, rejectUnknownSNI bool) f
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) parseServerName() string {
|
func (c *Config) parseServerName() string {
|
||||||
if IsFromMitm(c.ServerName) {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return c.ServerName
|
return c.ServerName
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,16 +444,6 @@ func (c *Config) GetTLSConfig(opts ...Option) *tls.Config {
|
|||||||
config.KeyLogWriter = writer
|
config.KeyLogWriter = writer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(c.EchConfigList) > 0 || len(c.EchServerKeys) > 0 {
|
|
||||||
err := ApplyECH(c, config)
|
|
||||||
if err != nil {
|
|
||||||
if c.EchForceQuery || errors.Cause(err) != dns.ErrEmptyResponse {
|
|
||||||
errors.LogError(context.Background(), err)
|
|
||||||
} else {
|
|
||||||
errors.LogInfo(context.Background(), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
@@ -477,12 +463,6 @@ func WithDestination(dest net.Destination) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithOverrideName(serverName string) Option {
|
|
||||||
return func(config *tls.Config) {
|
|
||||||
config.ServerName = serverName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithNextProto sets the ALPN values in TLS config.
|
// WithNextProto sets the ALPN values in TLS config.
|
||||||
func WithNextProto(protocol ...string) Option {
|
func WithNextProto(protocol ...string) Option {
|
||||||
return func(config *tls.Config) {
|
return func(config *tls.Config) {
|
||||||
@@ -523,7 +503,3 @@ func ParseCurveName(curveNames []string) []tls.CurveID {
|
|||||||
}
|
}
|
||||||
return curveIDs
|
return curveIDs
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsFromMitm(str string) bool {
|
|
||||||
return strings.ToLower(str) == "frommitm"
|
|
||||||
}
|
|
||||||
|
@@ -7,7 +7,6 @@
|
|||||||
package tls
|
package tls
|
||||||
|
|
||||||
import (
|
import (
|
||||||
internet "github.com/xtls/xray-core/transport/internet"
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
@@ -218,10 +217,6 @@ type Config struct {
|
|||||||
// @Document After allow_insecure (automatically), if the server's cert can't be verified by any of these names, pinned_peer_certificate_chain_sha256 will be tried.
|
// @Document After allow_insecure (automatically), if the server's cert can't be verified by any of these names, pinned_peer_certificate_chain_sha256 will be tried.
|
||||||
// @Critical
|
// @Critical
|
||||||
VerifyPeerCertInNames []string `protobuf:"bytes,17,rep,name=verify_peer_cert_in_names,json=verifyPeerCertInNames,proto3" json:"verify_peer_cert_in_names,omitempty"`
|
VerifyPeerCertInNames []string `protobuf:"bytes,17,rep,name=verify_peer_cert_in_names,json=verifyPeerCertInNames,proto3" json:"verify_peer_cert_in_names,omitempty"`
|
||||||
EchServerKeys []byte `protobuf:"bytes,18,opt,name=ech_server_keys,json=echServerKeys,proto3" json:"ech_server_keys,omitempty"`
|
|
||||||
EchConfigList string `protobuf:"bytes,19,opt,name=ech_config_list,json=echConfigList,proto3" json:"ech_config_list,omitempty"`
|
|
||||||
EchForceQuery bool `protobuf:"varint,20,opt,name=ech_force_query,json=echForceQuery,proto3" json:"ech_force_query,omitempty"`
|
|
||||||
EchSocketSettings *internet.SocketConfig `protobuf:"bytes,21,opt,name=ech_socket_settings,json=echSocketSettings,proto3" json:"ech_socket_settings,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@@ -366,34 +361,6 @@ func (x *Config) GetVerifyPeerCertInNames() []string {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetEchServerKeys() []byte {
|
|
||||||
if x != nil {
|
|
||||||
return x.EchServerKeys
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetEchConfigList() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.EchConfigList
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetEchForceQuery() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.EchForceQuery
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetEchSocketSettings() *internet.SocketConfig {
|
|
||||||
if x != nil {
|
|
||||||
return x.EchSocketSettings
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_transport_internet_tls_config_proto protoreflect.FileDescriptor
|
var File_transport_internet_tls_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_transport_internet_tls_config_proto_rawDesc = []byte{
|
var file_transport_internet_tls_config_proto_rawDesc = []byte{
|
||||||
@@ -401,96 +368,81 @@ var file_transport_internet_tls_config_proto_rawDesc = []byte{
|
|||||||
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x74, 0x6c, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
|
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x74, 0x6c, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1b, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e,
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1b, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e,
|
||||||
0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74,
|
0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74,
|
||||||
0x6c, 0x73, 0x1a, 0x1f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e,
|
0x6c, 0x73, 0x22, 0x83, 0x03, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
|
||||||
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72,
|
0x74, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
|
||||||
0x6f, 0x74, 0x6f, 0x22, 0x83, 0x03, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
|
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
|
||||||
0x61, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
|
0x63, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||||
0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66,
|
0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x44, 0x0a, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x18,
|
||||||
0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01,
|
0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
|
||||||
0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x44, 0x0a, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65,
|
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
|
||||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72,
|
0x74, 0x6c, 0x73, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x2e,
|
||||||
0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
|
0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x0d,
|
||||||
0x2e, 0x74, 0x6c, 0x73, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
|
0x6f, 0x63, 0x73, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x18, 0x04, 0x20,
|
||||||
0x2e, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a,
|
0x01, 0x28, 0x04, 0x52, 0x0c, 0x6f, 0x63, 0x73, 0x70, 0x53, 0x74, 0x61, 0x70, 0x6c, 0x69, 0x6e,
|
||||||
0x0d, 0x6f, 0x63, 0x73, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x18, 0x04,
|
0x67, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
|
||||||
0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6f, 0x63, 0x73, 0x70, 0x53, 0x74, 0x61, 0x70, 0x6c, 0x69,
|
0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x65, 0x72,
|
||||||
0x6e, 0x67, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
|
0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08,
|
||||||
0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x65,
|
0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
|
||||||
0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x19, 0x0a,
|
0x6b, 0x65, 0x79, 0x50, 0x61, 0x74, 0x68, 0x12, 0x28, 0x0a, 0x10, 0x4f, 0x6e, 0x65, 0x5f, 0x74,
|
||||||
0x08, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52,
|
0x69, 0x6d, 0x65, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28,
|
||||||
0x07, 0x6b, 0x65, 0x79, 0x50, 0x61, 0x74, 0x68, 0x12, 0x28, 0x0a, 0x10, 0x4f, 0x6e, 0x65, 0x5f,
|
0x08, 0x52, 0x0e, 0x4f, 0x6e, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x4c, 0x6f, 0x61, 0x64, 0x69, 0x6e,
|
||||||
0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x07, 0x20, 0x01,
|
0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e,
|
||||||
0x28, 0x08, 0x52, 0x0e, 0x4f, 0x6e, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x4c, 0x6f, 0x61, 0x64, 0x69,
|
0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x68, 0x61,
|
||||||
0x6e, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x69,
|
0x69, 0x6e, 0x22, 0x44, 0x0a, 0x05, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x45,
|
||||||
0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x68,
|
0x4e, 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x00, 0x12, 0x14, 0x0a,
|
||||||
0x61, 0x69, 0x6e, 0x22, 0x44, 0x0a, 0x05, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x0c,
|
0x10, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x56, 0x45, 0x52, 0x49, 0x46,
|
||||||
0x45, 0x4e, 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x00, 0x12, 0x14,
|
0x59, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59,
|
||||||
0x0a, 0x10, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x56, 0x45, 0x52, 0x49,
|
0x5f, 0x49, 0x53, 0x53, 0x55, 0x45, 0x10, 0x02, 0x22, 0x9a, 0x06, 0x0a, 0x06, 0x43, 0x6f, 0x6e,
|
||||||
0x46, 0x59, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54,
|
0x66, 0x69, 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x6e, 0x73,
|
||||||
0x59, 0x5f, 0x49, 0x53, 0x53, 0x55, 0x45, 0x10, 0x02, 0x22, 0xe9, 0x07, 0x0a, 0x06, 0x43, 0x6f,
|
0x65, 0x63, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c, 0x6c,
|
||||||
0x6e, 0x66, 0x69, 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x6e,
|
0x6f, 0x77, 0x49, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x12, 0x4a, 0x0a, 0x0b, 0x63, 0x65,
|
||||||
0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c,
|
0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||||
0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x12, 0x4a, 0x0a, 0x0b, 0x63,
|
0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74,
|
||||||
0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
|
0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74, 0x6c, 0x73, 0x2e, 0x43, 0x65,
|
||||||
0x32, 0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
|
0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69,
|
||||||
0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74, 0x6c, 0x73, 0x2e, 0x43,
|
0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
|
||||||
0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74,
|
0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x72,
|
||||||
0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65,
|
0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x5f,
|
||||||
0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65,
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c,
|
||||||
0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x6e, 0x65, 0x78, 0x74,
|
0x6e, 0x65, 0x78, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x3a, 0x0a, 0x19,
|
||||||
0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52,
|
0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x72,
|
||||||
0x0c, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x3a, 0x0a,
|
0x65, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||||
0x19, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f,
|
0x17, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65,
|
||||||
0x72, 0x65, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08,
|
0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x13, 0x64, 0x69, 0x73, 0x61,
|
||||||
0x52, 0x17, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52,
|
0x62, 0x6c, 0x65, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18,
|
||||||
0x65, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x13, 0x64, 0x69, 0x73,
|
0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x79,
|
||||||
0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x72, 0x6f, 0x6f, 0x74,
|
0x73, 0x74, 0x65, 0x6d, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x69, 0x6e, 0x5f,
|
||||||
0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53,
|
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d,
|
||||||
0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x69, 0x6e,
|
0x69, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x61, 0x78,
|
||||||
0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
|
0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
|
||||||
0x6d, 0x69, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x61,
|
0x6d, 0x61, 0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x69,
|
||||||
0x78, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52,
|
0x70, 0x68, 0x65, 0x72, 0x5f, 0x73, 0x75, 0x69, 0x74, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28,
|
||||||
0x0a, 0x6d, 0x61, 0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x63,
|
0x09, 0x52, 0x0c, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x53, 0x75, 0x69, 0x74, 0x65, 0x73, 0x12,
|
||||||
0x69, 0x70, 0x68, 0x65, 0x72, 0x5f, 0x73, 0x75, 0x69, 0x74, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01,
|
0x20, 0x0a, 0x0b, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x18, 0x0b,
|
||||||
0x28, 0x09, 0x52, 0x0c, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x53, 0x75, 0x69, 0x74, 0x65, 0x73,
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e,
|
||||||
0x12, 0x20, 0x0a, 0x0b, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x18,
|
0x74, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x75, 0x6e, 0x6b, 0x6e,
|
||||||
0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69,
|
0x6f, 0x77, 0x6e, 0x5f, 0x73, 0x6e, 0x69, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x72,
|
||||||
0x6e, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x75, 0x6e, 0x6b,
|
0x65, 0x6a, 0x65, 0x63, 0x74, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x53, 0x6e, 0x69, 0x12,
|
||||||
0x6e, 0x6f, 0x77, 0x6e, 0x5f, 0x73, 0x6e, 0x69, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10,
|
0x4e, 0x0a, 0x24, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x63,
|
||||||
0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x53, 0x6e, 0x69,
|
0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e,
|
||||||
0x12, 0x4e, 0x0a, 0x24, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x5f,
|
0x5f, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x20, 0x70,
|
||||||
0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x69,
|
0x69, 0x6e, 0x6e, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
|
||||||
0x6e, 0x5f, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x20,
|
0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x68, 0x61, 0x32, 0x35, 0x36, 0x12,
|
||||||
0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
|
0x57, 0x0a, 0x29, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x63,
|
||||||
0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x68, 0x61, 0x32, 0x35, 0x36,
|
0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69,
|
||||||
0x12, 0x57, 0x0a, 0x29, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x5f,
|
0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x18, 0x0e, 0x20, 0x03,
|
||||||
0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x75, 0x62, 0x6c,
|
0x28, 0x0c, 0x52, 0x24, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x43, 0x65,
|
||||||
0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x18, 0x0e, 0x20,
|
0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b,
|
||||||
0x03, 0x28, 0x0c, 0x52, 0x24, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x43,
|
0x65, 0x79, 0x53, 0x68, 0x61, 0x32, 0x35, 0x36, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x61, 0x73, 0x74,
|
||||||
0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63,
|
0x65, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x6c, 0x6f, 0x67, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09,
|
||||||
0x4b, 0x65, 0x79, 0x53, 0x68, 0x61, 0x32, 0x35, 0x36, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x61, 0x73,
|
0x52, 0x0c, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x4c, 0x6f, 0x67, 0x12, 0x2b,
|
||||||
0x74, 0x65, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x6c, 0x6f, 0x67, 0x18, 0x0f, 0x20, 0x01, 0x28,
|
0x0a, 0x11, 0x63, 0x75, 0x72, 0x76, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e,
|
||||||
0x09, 0x52, 0x0c, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x4c, 0x6f, 0x67, 0x12,
|
0x63, 0x65, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x63, 0x75, 0x72, 0x76, 0x65,
|
||||||
0x2b, 0x0a, 0x11, 0x63, 0x75, 0x72, 0x76, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65,
|
0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x19, 0x76,
|
||||||
0x6e, 0x63, 0x65, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x63, 0x75, 0x72, 0x76,
|
0x65, 0x72, 0x69, 0x66, 0x79, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x5f,
|
||||||
0x65, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x19,
|
0x69, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x11, 0x20, 0x03, 0x28, 0x09, 0x52, 0x15,
|
||||||
0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x63, 0x65, 0x72, 0x74,
|
0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x50, 0x65, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x49, 0x6e,
|
||||||
0x5f, 0x69, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x11, 0x20, 0x03, 0x28, 0x09, 0x52,
|
0x4e, 0x61, 0x6d, 0x65, 0x73, 0x42, 0x73, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61,
|
||||||
0x15, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x50, 0x65, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x49,
|
|
||||||
0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x65, 0x63, 0x68, 0x5f, 0x73, 0x65,
|
|
||||||
0x72, 0x76, 0x65, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0c, 0x52,
|
|
||||||
0x0d, 0x65, 0x63, 0x68, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x26,
|
|
||||||
0x0a, 0x0f, 0x65, 0x63, 0x68, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x6c, 0x69, 0x73,
|
|
||||||
0x74, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x65, 0x63, 0x68, 0x43, 0x6f, 0x6e, 0x66,
|
|
||||||
0x69, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x65, 0x63, 0x68, 0x5f, 0x66, 0x6f,
|
|
||||||
0x72, 0x63, 0x65, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52,
|
|
||||||
0x0d, 0x65, 0x63, 0x68, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x55,
|
|
||||||
0x0a, 0x13, 0x65, 0x63, 0x68, 0x5f, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x73, 0x65, 0x74,
|
|
||||||
0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 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, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66,
|
|
||||||
0x69, 0x67, 0x52, 0x11, 0x65, 0x63, 0x68, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x65, 0x74,
|
|
||||||
0x74, 0x69, 0x6e, 0x67, 0x73, 0x42, 0x73, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61,
|
|
||||||
0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65,
|
0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65,
|
||||||
0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74, 0x6c, 0x73, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68,
|
0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74, 0x6c, 0x73, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68,
|
||||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79,
|
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79,
|
||||||
@@ -519,17 +471,15 @@ var file_transport_internet_tls_config_proto_goTypes = []any{
|
|||||||
(Certificate_Usage)(0), // 0: xray.transport.internet.tls.Certificate.Usage
|
(Certificate_Usage)(0), // 0: xray.transport.internet.tls.Certificate.Usage
|
||||||
(*Certificate)(nil), // 1: xray.transport.internet.tls.Certificate
|
(*Certificate)(nil), // 1: xray.transport.internet.tls.Certificate
|
||||||
(*Config)(nil), // 2: xray.transport.internet.tls.Config
|
(*Config)(nil), // 2: xray.transport.internet.tls.Config
|
||||||
(*internet.SocketConfig)(nil), // 3: xray.transport.internet.SocketConfig
|
|
||||||
}
|
}
|
||||||
var file_transport_internet_tls_config_proto_depIdxs = []int32{
|
var file_transport_internet_tls_config_proto_depIdxs = []int32{
|
||||||
0, // 0: xray.transport.internet.tls.Certificate.usage:type_name -> xray.transport.internet.tls.Certificate.Usage
|
0, // 0: xray.transport.internet.tls.Certificate.usage:type_name -> xray.transport.internet.tls.Certificate.Usage
|
||||||
1, // 1: xray.transport.internet.tls.Config.certificate:type_name -> xray.transport.internet.tls.Certificate
|
1, // 1: xray.transport.internet.tls.Config.certificate:type_name -> xray.transport.internet.tls.Certificate
|
||||||
3, // 2: xray.transport.internet.tls.Config.ech_socket_settings:type_name -> xray.transport.internet.SocketConfig
|
2, // [2:2] is the sub-list for method output_type
|
||||||
3, // [3:3] is the sub-list for method output_type
|
2, // [2:2] is the sub-list for method input_type
|
||||||
3, // [3:3] is the sub-list for method input_type
|
2, // [2:2] is the sub-list for extension type_name
|
||||||
3, // [3:3] is the sub-list for extension type_name
|
2, // [2:2] is the sub-list for extension extendee
|
||||||
3, // [3:3] is the sub-list for extension extendee
|
0, // [0:2] is the sub-list for field type_name
|
||||||
0, // [0:3] is the sub-list for field type_name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_transport_internet_tls_config_proto_init() }
|
func init() { file_transport_internet_tls_config_proto_init() }
|
||||||
|
@@ -6,8 +6,6 @@ option go_package = "github.com/xtls/xray-core/transport/internet/tls";
|
|||||||
option java_package = "com.xray.transport.internet.tls";
|
option java_package = "com.xray.transport.internet.tls";
|
||||||
option java_multiple_files = true;
|
option java_multiple_files = true;
|
||||||
|
|
||||||
import "transport/internet/config.proto";
|
|
||||||
|
|
||||||
message Certificate {
|
message Certificate {
|
||||||
// TLS certificate in x509 format.
|
// TLS certificate in x509 format.
|
||||||
bytes certificate = 1;
|
bytes certificate = 1;
|
||||||
@@ -93,12 +91,4 @@ message Config {
|
|||||||
@Critical
|
@Critical
|
||||||
*/
|
*/
|
||||||
repeated string verify_peer_cert_in_names = 17;
|
repeated string verify_peer_cert_in_names = 17;
|
||||||
|
|
||||||
bytes ech_server_keys = 18;
|
|
||||||
|
|
||||||
string ech_config_list = 19;
|
|
||||||
|
|
||||||
bool ech_force_query = 20;
|
|
||||||
|
|
||||||
SocketConfig ech_socket_settings = 21;
|
|
||||||
}
|
}
|
||||||
|
@@ -1,412 +0,0 @@
|
|||||||
package tls
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"crypto/ecdh"
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/tls"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
|
||||||
utls "github.com/refraction-networking/utls"
|
|
||||||
"github.com/xtls/xray-core/common/crypto"
|
|
||||||
dns2 "github.com/xtls/xray-core/features/dns"
|
|
||||||
"golang.org/x/net/http2"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
|
||||||
"github.com/xtls/reality"
|
|
||||||
"github.com/xtls/reality/hpke"
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/common/utils"
|
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
|
||||||
"golang.org/x/crypto/cryptobyte"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ApplyECH(c *Config, config *tls.Config) error {
|
|
||||||
var ECHConfig []byte
|
|
||||||
var err error
|
|
||||||
|
|
||||||
var nameToQuery string
|
|
||||||
if net.ParseAddress(config.ServerName).Family().IsDomain() {
|
|
||||||
nameToQuery = config.ServerName
|
|
||||||
}
|
|
||||||
var DNSServer string
|
|
||||||
|
|
||||||
// for server
|
|
||||||
if len(c.EchServerKeys) != 0 {
|
|
||||||
KeySets, err := ConvertToGoECHKeys(c.EchServerKeys)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("Failed to unmarshal ECHKeySetList: ", err)
|
|
||||||
}
|
|
||||||
config.EncryptedClientHelloKeys = KeySets
|
|
||||||
}
|
|
||||||
|
|
||||||
// for client
|
|
||||||
if len(c.EchConfigList) != 0 {
|
|
||||||
defer func() {
|
|
||||||
// if failed to get ECHConfig, use an invalid one to make connection fail
|
|
||||||
if err != nil {
|
|
||||||
if c.EchForceQuery {
|
|
||||||
ECHConfig = []byte{1, 1, 4, 5, 1, 4}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
config.EncryptedClientHelloConfigList = ECHConfig
|
|
||||||
}()
|
|
||||||
// direct base64 config
|
|
||||||
if strings.Contains(c.EchConfigList, "://") {
|
|
||||||
// query config from dns
|
|
||||||
parts := strings.Split(c.EchConfigList, "+")
|
|
||||||
if len(parts) == 2 {
|
|
||||||
// parse ECH DNS server in format of "example.com+https://1.1.1.1/dns-query"
|
|
||||||
nameToQuery = parts[0]
|
|
||||||
DNSServer = parts[1]
|
|
||||||
} else if len(parts) == 1 {
|
|
||||||
// normal format
|
|
||||||
DNSServer = parts[0]
|
|
||||||
} else {
|
|
||||||
return errors.New("Invalid ECH DNS server format: ", c.EchConfigList)
|
|
||||||
}
|
|
||||||
if nameToQuery == "" {
|
|
||||||
return errors.New("Using DNS for ECH Config needs serverName or use Server format example.com+https://1.1.1.1/dns-query")
|
|
||||||
}
|
|
||||||
ECHConfig, err = QueryRecord(nameToQuery, DNSServer, c.EchForceQuery, c.EchSocketSettings)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("Failed to query ECH DNS record for domain: ", nameToQuery, " at server: ", DNSServer).Base(err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ECHConfig, err = base64.StdEncoding.DecodeString(c.EchConfigList)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("Failed to unmarshal ECHConfigList: ", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type ECHConfigCache struct {
|
|
||||||
configRecord atomic.Pointer[echConfigRecord]
|
|
||||||
// updateLock is not for preventing concurrent read/write, but for preventing concurrent update
|
|
||||||
UpdateLock sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
type echConfigRecord struct {
|
|
||||||
config []byte
|
|
||||||
expire time.Time
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
// key value must be like this: "example.com|udp://1.1.1.1"
|
|
||||||
GlobalECHConfigCache = utils.NewTypedSyncMap[string, *ECHConfigCache]()
|
|
||||||
clientForECHDOH = utils.NewTypedSyncMap[string, *http.Client]()
|
|
||||||
)
|
|
||||||
|
|
||||||
// Update updates the ECH config for given domain and server.
|
|
||||||
// this method is concurrent safe, only one update request will be sent, others get the cache.
|
|
||||||
// if isLockedUpdate is true, it will not try to acquire the lock.
|
|
||||||
func (c *ECHConfigCache) Update(domain string, server string, isLockedUpdate bool, forceQuery bool, sockopt *internet.SocketConfig) ([]byte, error) {
|
|
||||||
if !isLockedUpdate {
|
|
||||||
c.UpdateLock.Lock()
|
|
||||||
defer c.UpdateLock.Unlock()
|
|
||||||
}
|
|
||||||
// Double check cache after acquiring lock
|
|
||||||
configRecord := c.configRecord.Load()
|
|
||||||
if configRecord.expire.After(time.Now()) {
|
|
||||||
errors.LogDebug(context.Background(), "Cache hit for domain after double check: ", domain)
|
|
||||||
return configRecord.config, configRecord.err
|
|
||||||
}
|
|
||||||
// Query ECH config from DNS server
|
|
||||||
errors.LogDebug(context.Background(), "Trying to query ECH config for domain: ", domain, " with ECH server: ", server)
|
|
||||||
echConfig, ttl, err := dnsQuery(server, domain, sockopt)
|
|
||||||
if err != nil {
|
|
||||||
if forceQuery || ttl == 0 {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
configRecord = &echConfigRecord{
|
|
||||||
config: echConfig,
|
|
||||||
expire: time.Now().Add(time.Duration(ttl) * time.Second),
|
|
||||||
err: err,
|
|
||||||
}
|
|
||||||
c.configRecord.Store(configRecord)
|
|
||||||
return configRecord.config, configRecord.err
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryRecord returns the ECH config for given domain.
|
|
||||||
// If the record is not in cache or expired, it will query the DNS server and update the cache.
|
|
||||||
func QueryRecord(domain string, server string, forceQuery bool, sockopt *internet.SocketConfig) ([]byte, error) {
|
|
||||||
GlobalECHConfigCacheKey := domain + "|" + server + "|" + fmt.Sprintf("%p", sockopt)
|
|
||||||
echConfigCache, ok := GlobalECHConfigCache.Load(GlobalECHConfigCacheKey)
|
|
||||||
if !ok {
|
|
||||||
echConfigCache = &ECHConfigCache{}
|
|
||||||
echConfigCache.configRecord.Store(&echConfigRecord{})
|
|
||||||
echConfigCache, _ = GlobalECHConfigCache.LoadOrStore(GlobalECHConfigCacheKey, echConfigCache)
|
|
||||||
}
|
|
||||||
configRecord := echConfigCache.configRecord.Load()
|
|
||||||
if configRecord.expire.After(time.Now()) {
|
|
||||||
errors.LogDebug(context.Background(), "Cache hit for domain: ", domain)
|
|
||||||
return configRecord.config, configRecord.err
|
|
||||||
}
|
|
||||||
|
|
||||||
// If expire is zero value, it means we are in initial state, wait for the query to finish
|
|
||||||
// otherwise return old value immediately and update in a goroutine
|
|
||||||
// but if the cache is too old, wait for update
|
|
||||||
if configRecord.expire == (time.Time{}) || configRecord.expire.Add(time.Hour*6).Before(time.Now()) {
|
|
||||||
return echConfigCache.Update(domain, server, false, forceQuery, sockopt)
|
|
||||||
} else {
|
|
||||||
// If someone already acquired the lock, it means it is updating, do not start another update goroutine
|
|
||||||
if echConfigCache.UpdateLock.TryLock() {
|
|
||||||
go func() {
|
|
||||||
defer echConfigCache.UpdateLock.Unlock()
|
|
||||||
echConfigCache.Update(domain, server, true, forceQuery, sockopt)
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
return configRecord.config, configRecord.err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// dnsQuery is the real func for sending type65 query for given domain to given DNS server.
|
|
||||||
// return ECH config, TTL and error
|
|
||||||
func dnsQuery(server string, domain string, sockopt *internet.SocketConfig) ([]byte, uint32, error) {
|
|
||||||
m := new(dns.Msg)
|
|
||||||
var dnsResolve []byte
|
|
||||||
m.SetQuestion(dns.Fqdn(domain), dns.TypeHTTPS)
|
|
||||||
// for DOH server
|
|
||||||
if strings.HasPrefix(server, "https://") || strings.HasPrefix(server, "h2c://") {
|
|
||||||
h2c := strings.HasPrefix(server, "h2c://")
|
|
||||||
m.SetEdns0(4096, false) // 4096 is the buffer size, false means no DNSSEC
|
|
||||||
padding := &dns.EDNS0_PADDING{Padding: make([]byte, int(crypto.RandBetween(100, 300)))}
|
|
||||||
if opt := m.IsEdns0(); opt != nil {
|
|
||||||
opt.Option = append(opt.Option, padding)
|
|
||||||
}
|
|
||||||
// always 0 in DOH
|
|
||||||
m.Id = 0
|
|
||||||
msg, err := m.Pack()
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
var client *http.Client
|
|
||||||
serverKey := server + "|" + fmt.Sprintf("%p", sockopt)
|
|
||||||
if client, _ = clientForECHDOH.Load(serverKey); client == nil {
|
|
||||||
// All traffic sent by core should via xray's internet.DialSystem
|
|
||||||
// This involves the behavior of some Android VPN GUI clients
|
|
||||||
tr := &http2.Transport{
|
|
||||||
IdleConnTimeout: net.ConnIdleTimeout,
|
|
||||||
ReadIdleTimeout: net.ChromeH2KeepAlivePeriod,
|
|
||||||
DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) {
|
|
||||||
dest, err := net.ParseDestination(network + ":" + addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var conn net.Conn
|
|
||||||
|
|
||||||
conn, err = internet.DialSystem(ctx, dest, sockopt)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !h2c {
|
|
||||||
u, err := url.Parse(server)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
conn = utls.UClient(conn, &utls.Config{ServerName: u.Hostname()}, utls.HelloChrome_Auto)
|
|
||||||
if err := conn.(*utls.UConn).HandshakeContext(ctx); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return conn, nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
c := &http.Client{
|
|
||||||
Timeout: 5 * time.Second,
|
|
||||||
Transport: tr,
|
|
||||||
}
|
|
||||||
client, _ = clientForECHDOH.LoadOrStore(serverKey, c)
|
|
||||||
}
|
|
||||||
req, err := http.NewRequest("POST", server, bytes.NewReader(msg))
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
req.Header.Set("Accept", "application/dns-message")
|
|
||||||
req.Header.Set("Content-Type", "application/dns-message")
|
|
||||||
req.Header.Set("X-Padding", strings.Repeat("X", int(crypto.RandBetween(100, 1000))))
|
|
||||||
resp, err := client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
respBody, err := io.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
return nil, 0, errors.New("query failed with response code:", resp.StatusCode)
|
|
||||||
}
|
|
||||||
dnsResolve = respBody
|
|
||||||
} else if strings.HasPrefix(server, "udp://") { // for classic udp dns server
|
|
||||||
udpServerAddr := server[len("udp://"):]
|
|
||||||
// default port 53 if not specified
|
|
||||||
if !strings.Contains(udpServerAddr, ":") {
|
|
||||||
udpServerAddr = udpServerAddr + ":53"
|
|
||||||
}
|
|
||||||
dest, err := net.ParseDestination("udp" + ":" + udpServerAddr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, errors.New("failed to parse udp dns server ", udpServerAddr, " for ECH: ", err)
|
|
||||||
}
|
|
||||||
dnsTimeoutCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
||||||
defer cancel()
|
|
||||||
// use xray's internet.DialSystem as mentioned above
|
|
||||||
conn, err := internet.DialSystem(dnsTimeoutCtx, dest, sockopt)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
err := conn.Close()
|
|
||||||
if err != nil {
|
|
||||||
errors.LogDebug(context.Background(), "Failed to close connection: ", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
msg, err := m.Pack()
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
conn.Write(msg)
|
|
||||||
udpResponse := make([]byte, 512)
|
|
||||||
conn.SetReadDeadline(time.Now().Add(5 * time.Second))
|
|
||||||
_, err = conn.Read(udpResponse)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
dnsResolve = udpResponse
|
|
||||||
}
|
|
||||||
respMsg := new(dns.Msg)
|
|
||||||
err := respMsg.Unpack(dnsResolve)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, errors.New("failed to unpack dns response for ECH: ", err)
|
|
||||||
}
|
|
||||||
if len(respMsg.Answer) > 0 {
|
|
||||||
for _, answer := range respMsg.Answer {
|
|
||||||
if https, ok := answer.(*dns.HTTPS); ok && https.Hdr.Name == dns.Fqdn(domain) {
|
|
||||||
for _, v := range https.Value {
|
|
||||||
if echConfig, ok := v.(*dns.SVCBECHConfig); ok {
|
|
||||||
errors.LogDebug(context.Background(), "Get ECH config:", echConfig.String(), " TTL:", respMsg.Answer[0].Header().Ttl)
|
|
||||||
return echConfig.ECH, answer.Header().Ttl, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, dns2.DefaultTTL, dns2.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
// reference github.com/OmarTariq612/goech
|
|
||||||
func MarshalBinary(ech reality.EchConfig) ([]byte, error) {
|
|
||||||
var b cryptobyte.Builder
|
|
||||||
b.AddUint16(ech.Version)
|
|
||||||
b.AddUint16LengthPrefixed(func(child *cryptobyte.Builder) {
|
|
||||||
child.AddUint8(ech.ConfigID)
|
|
||||||
child.AddUint16(ech.KemID)
|
|
||||||
child.AddUint16(uint16(len(ech.PublicKey)))
|
|
||||||
child.AddBytes(ech.PublicKey)
|
|
||||||
child.AddUint16LengthPrefixed(func(child *cryptobyte.Builder) {
|
|
||||||
for _, cipherSuite := range ech.SymmetricCipherSuite {
|
|
||||||
child.AddUint16(cipherSuite.KDFID)
|
|
||||||
child.AddUint16(cipherSuite.AEADID)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
child.AddUint8(ech.MaxNameLength)
|
|
||||||
child.AddUint8(uint8(len(ech.PublicName)))
|
|
||||||
child.AddBytes(ech.PublicName)
|
|
||||||
child.AddUint16LengthPrefixed(func(child *cryptobyte.Builder) {
|
|
||||||
for _, extention := range ech.Extensions {
|
|
||||||
child.AddUint16(extention.Type)
|
|
||||||
child.AddBytes(extention.Data)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
return b.Bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
var ErrInvalidLen = errors.New("goech: invalid length")
|
|
||||||
|
|
||||||
func ConvertToGoECHKeys(data []byte) ([]tls.EncryptedClientHelloKey, error) {
|
|
||||||
var keys []tls.EncryptedClientHelloKey
|
|
||||||
s := cryptobyte.String(data)
|
|
||||||
for !s.Empty() {
|
|
||||||
if len(s) < 2 {
|
|
||||||
return keys, ErrInvalidLen
|
|
||||||
}
|
|
||||||
keyLength := int(binary.BigEndian.Uint16(s[:2]))
|
|
||||||
if len(s) < keyLength+4 {
|
|
||||||
return keys, ErrInvalidLen
|
|
||||||
}
|
|
||||||
configLength := int(binary.BigEndian.Uint16(s[keyLength+2 : keyLength+4]))
|
|
||||||
if len(s) < 2+keyLength+2+configLength {
|
|
||||||
return keys, ErrInvalidLen
|
|
||||||
}
|
|
||||||
child := cryptobyte.String(s[:2+keyLength+2+configLength])
|
|
||||||
var (
|
|
||||||
sk, config cryptobyte.String
|
|
||||||
)
|
|
||||||
if !child.ReadUint16LengthPrefixed(&sk) || !child.ReadUint16LengthPrefixed(&config) || !child.Empty() {
|
|
||||||
return keys, ErrInvalidLen
|
|
||||||
}
|
|
||||||
if !s.Skip(2 + keyLength + 2 + configLength) {
|
|
||||||
return keys, ErrInvalidLen
|
|
||||||
}
|
|
||||||
keys = append(keys, tls.EncryptedClientHelloKey{
|
|
||||||
Config: config,
|
|
||||||
PrivateKey: sk,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return keys, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const ExtensionEncryptedClientHello = 0xfe0d
|
|
||||||
const KDF_HKDF_SHA384 = 0x0002
|
|
||||||
const KDF_HKDF_SHA512 = 0x0003
|
|
||||||
|
|
||||||
func GenerateECHKeySet(configID uint8, domain string, kem uint16) (reality.EchConfig, []byte, error) {
|
|
||||||
config := reality.EchConfig{
|
|
||||||
Version: ExtensionEncryptedClientHello,
|
|
||||||
ConfigID: configID,
|
|
||||||
PublicName: []byte(domain),
|
|
||||||
KemID: kem,
|
|
||||||
SymmetricCipherSuite: []reality.EchCipher{
|
|
||||||
{KDFID: hpke.KDF_HKDF_SHA256, AEADID: hpke.AEAD_AES_128_GCM},
|
|
||||||
{KDFID: hpke.KDF_HKDF_SHA256, AEADID: hpke.AEAD_AES_256_GCM},
|
|
||||||
{KDFID: hpke.KDF_HKDF_SHA256, AEADID: hpke.AEAD_ChaCha20Poly1305},
|
|
||||||
{KDFID: KDF_HKDF_SHA384, AEADID: hpke.AEAD_AES_128_GCM},
|
|
||||||
{KDFID: KDF_HKDF_SHA384, AEADID: hpke.AEAD_AES_256_GCM},
|
|
||||||
{KDFID: KDF_HKDF_SHA384, AEADID: hpke.AEAD_ChaCha20Poly1305},
|
|
||||||
{KDFID: KDF_HKDF_SHA512, AEADID: hpke.AEAD_AES_128_GCM},
|
|
||||||
{KDFID: KDF_HKDF_SHA512, AEADID: hpke.AEAD_AES_256_GCM},
|
|
||||||
{KDFID: KDF_HKDF_SHA512, AEADID: hpke.AEAD_ChaCha20Poly1305},
|
|
||||||
},
|
|
||||||
MaxNameLength: 0,
|
|
||||||
Extensions: nil,
|
|
||||||
}
|
|
||||||
// if kem == hpke.DHKEM_X25519_HKDF_SHA256 {
|
|
||||||
curve := ecdh.X25519()
|
|
||||||
priv := make([]byte, 32) //x25519
|
|
||||||
_, err := io.ReadFull(rand.Reader, priv)
|
|
||||||
if err != nil {
|
|
||||||
return config, nil, err
|
|
||||||
}
|
|
||||||
privKey, _ := curve.NewPrivateKey(priv)
|
|
||||||
config.PublicKey = privKey.PublicKey().Bytes()
|
|
||||||
return config, priv, nil
|
|
||||||
// }
|
|
||||||
// TODO: add mlkem768 (former kyber768 draft00). The golang mlkem private key is 64 bytes seed?
|
|
||||||
}
|
|
@@ -1,90 +0,0 @@
|
|||||||
package tls
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestECHDial(t *testing.T) {
|
|
||||||
config := &Config{
|
|
||||||
ServerName: "cloudflare.com",
|
|
||||||
EchConfigList: "encryptedsni.com+udp://1.1.1.1",
|
|
||||||
}
|
|
||||||
// test concurrent Dial(to test cache problem)
|
|
||||||
wg := sync.WaitGroup{}
|
|
||||||
for range 10 {
|
|
||||||
wg.Add(1)
|
|
||||||
go func() {
|
|
||||||
TLSConfig := config.GetTLSConfig()
|
|
||||||
TLSConfig.NextProtos = []string{"http/1.1"}
|
|
||||||
client := &http.Client{
|
|
||||||
Transport: &http.Transport{
|
|
||||||
TLSClientConfig: TLSConfig,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
resp, err := client.Get("https://cloudflare.com/cdn-cgi/trace")
|
|
||||||
common.Must(err)
|
|
||||||
defer resp.Body.Close()
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
|
||||||
common.Must(err)
|
|
||||||
if !strings.Contains(string(body), "sni=encrypted") {
|
|
||||||
t.Error("ECH Dial success but SNI is not encrypted")
|
|
||||||
}
|
|
||||||
wg.Done()
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
wg.Wait()
|
|
||||||
// check cache
|
|
||||||
echConfigCache, ok := GlobalECHConfigCache.Load("encryptedsni.com|udp://1.1.1.1" + "|" + fmt.Sprintf("%p", config.EchSocketSettings))
|
|
||||||
if !ok {
|
|
||||||
t.Error("ECH config cache not found")
|
|
||||||
|
|
||||||
}
|
|
||||||
ok = echConfigCache.UpdateLock.TryLock()
|
|
||||||
if !ok {
|
|
||||||
t.Error("ECH config cache dead lock detected")
|
|
||||||
}
|
|
||||||
echConfigCache.UpdateLock.Unlock()
|
|
||||||
configRecord := echConfigCache.configRecord.Load()
|
|
||||||
if configRecord == nil {
|
|
||||||
t.Error("ECH config record not found in cache")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestECHDialFail(t *testing.T) {
|
|
||||||
config := &Config{
|
|
||||||
ServerName: "cloudflare.com",
|
|
||||||
EchConfigList: "udp://1.1.1.1",
|
|
||||||
}
|
|
||||||
TLSConfig := config.GetTLSConfig()
|
|
||||||
TLSConfig.NextProtos = []string{"http/1.1"}
|
|
||||||
client := &http.Client{
|
|
||||||
Transport: &http.Transport{
|
|
||||||
TLSClientConfig: TLSConfig,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
resp, err := client.Get("https://cloudflare.com/cdn-cgi/trace")
|
|
||||||
common.Must(err)
|
|
||||||
defer resp.Body.Close()
|
|
||||||
_, err = io.ReadAll(resp.Body)
|
|
||||||
common.Must(err)
|
|
||||||
// check cache
|
|
||||||
echConfigCache, ok := GlobalECHConfigCache.Load("cloudflare.com|udp://1.1.1.1" + "|" + fmt.Sprintf("%p", config.EchSocketSettings))
|
|
||||||
if !ok {
|
|
||||||
t.Error("ECH config cache not found")
|
|
||||||
}
|
|
||||||
configRecord := echConfigCache.configRecord.Load()
|
|
||||||
if configRecord == nil {
|
|
||||||
t.Error("ECH config record not found in cache")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if configRecord.err == nil {
|
|
||||||
t.Error("unexpected nil error in ECH config record")
|
|
||||||
}
|
|
||||||
}
|
|
@@ -134,7 +134,6 @@ func copyConfig(c *tls.Config) *utls.Config {
|
|||||||
InsecureSkipVerify: c.InsecureSkipVerify,
|
InsecureSkipVerify: c.InsecureSkipVerify,
|
||||||
VerifyPeerCertificate: c.VerifyPeerCertificate,
|
VerifyPeerCertificate: c.VerifyPeerCertificate,
|
||||||
KeyLogWriter: c.KeyLogWriter,
|
KeyLogWriter: c.KeyLogWriter,
|
||||||
EncryptedClientHelloConfigList: c.EncryptedClientHelloConfigList,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -44,10 +44,6 @@ 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)
|
||||||
@@ -66,15 +62,9 @@ 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() {
|
||||||
v.Lock()
|
|
||||||
defer v.Unlock()
|
|
||||||
// sometimes the entry is already removed by others, don't close again
|
|
||||||
if entry == v.conn {
|
|
||||||
cancel()
|
cancel()
|
||||||
v.removeRay()
|
v.RemoveRay()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
timer := signal.CancelAfterInactivity(ctx, removeRay, time.Minute)
|
timer := signal.CancelAfterInactivity(ctx, removeRay, time.Minute)
|
||||||
|
|
||||||
@@ -83,7 +73,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,
|
||||||
|
@@ -40,14 +40,6 @@ func ListenUDP(ctx context.Context, address net.Address, port net.Port, streamSe
|
|||||||
opt(hub)
|
opt(hub)
|
||||||
}
|
}
|
||||||
|
|
||||||
if address.Family().IsDomain() && address.Domain() == "localhost" {
|
|
||||||
address = net.LocalHostIP
|
|
||||||
}
|
|
||||||
|
|
||||||
if address.Family().IsDomain() {
|
|
||||||
return nil, errors.New("domain address is not allowed for listening: ", address.Domain())
|
|
||||||
}
|
|
||||||
|
|
||||||
var sockopt *internet.SocketConfig
|
var sockopt *internet.SocketConfig
|
||||||
if streamSettings != nil {
|
if streamSettings != nil {
|
||||||
sockopt = streamSettings.SocketSettings
|
sockopt = streamSettings.SocketSettings
|
||||||
|
Reference in New Issue
Block a user