Finalmask: Add XDNS (relies mKCP, like DNSTT), header-*, mkcp-* (#5560)

And https://github.com/XTLS/Xray-core/pull/5560#issuecomment-3825430761
This commit is contained in:
LjhAUMEM authored and GitHub committed 2026-01-31 13:53:19 +00:00
1 parent 5b849d51a9
commit c180c5980c
92 files changed
+5549 -2060

No files matched your search

-55
View File
@@ -4,72 +4,17 @@ import (
"sort" "sort"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/transport/internet/headers/dns"
"github.com/xtls/xray-core/transport/internet/headers/http" "github.com/xtls/xray-core/transport/internet/headers/http"
"github.com/xtls/xray-core/transport/internet/headers/noop" "github.com/xtls/xray-core/transport/internet/headers/noop"
"github.com/xtls/xray-core/transport/internet/headers/srtp"
"github.com/xtls/xray-core/transport/internet/headers/tls"
"github.com/xtls/xray-core/transport/internet/headers/utp"
"github.com/xtls/xray-core/transport/internet/headers/wechat"
"github.com/xtls/xray-core/transport/internet/headers/wireguard"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
) )
type NoOpAuthenticator struct{}
func (NoOpAuthenticator) Build() (proto.Message, error) {
return new(noop.Config), nil
}
type NoOpConnectionAuthenticator struct{} type NoOpConnectionAuthenticator struct{}
func (NoOpConnectionAuthenticator) Build() (proto.Message, error) { func (NoOpConnectionAuthenticator) Build() (proto.Message, error) {
return new(noop.ConnectionConfig), nil return new(noop.ConnectionConfig), nil
} }
type SRTPAuthenticator struct{}
func (SRTPAuthenticator) Build() (proto.Message, error) {
return new(srtp.Config), nil
}
type UTPAuthenticator struct{}
func (UTPAuthenticator) Build() (proto.Message, error) {
return new(utp.Config), nil
}
type WechatVideoAuthenticator struct{}
func (WechatVideoAuthenticator) Build() (proto.Message, error) {
return new(wechat.VideoConfig), nil
}
type WireguardAuthenticator struct{}
func (WireguardAuthenticator) Build() (proto.Message, error) {
return new(wireguard.WireguardConfig), nil
}
type DNSAuthenticator struct {
Domain string `json:"domain"`
}
func (v *DNSAuthenticator) Build() (proto.Message, error) {
config := new(dns.Config)
config.Domain = "www.baidu.com"
if len(v.Domain) > 0 {
config.Domain = v.Domain
}
return config, nil
}
type DTLSAuthenticator struct{}
func (DTLSAuthenticator) Build() (proto.Message, error) {
return new(tls.PacketConfig), nil
}
type AuthenticatorRequest struct { type AuthenticatorRequest struct {
Version string `json:"version"` Version string `json:"version"`
Method string `json:"method"` Method string `json:"method"`
+122 -37
View File
@@ -16,7 +16,16 @@ import (
"github.com/xtls/xray-core/common/platform/filesystem" "github.com/xtls/xray-core/common/platform/filesystem"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/finalmask/header/dns"
"github.com/xtls/xray-core/transport/internet/finalmask/header/dtls"
"github.com/xtls/xray-core/transport/internet/finalmask/header/srtp"
"github.com/xtls/xray-core/transport/internet/finalmask/header/utp"
"github.com/xtls/xray-core/transport/internet/finalmask/header/wechat"
"github.com/xtls/xray-core/transport/internet/finalmask/header/wireguard"
"github.com/xtls/xray-core/transport/internet/finalmask/mkcp/aes128gcm"
"github.com/xtls/xray-core/transport/internet/finalmask/mkcp/original"
"github.com/xtls/xray-core/transport/internet/finalmask/salamander" "github.com/xtls/xray-core/transport/internet/finalmask/salamander"
"github.com/xtls/xray-core/transport/internet/finalmask/xdns"
"github.com/xtls/xray-core/transport/internet/httpupgrade" "github.com/xtls/xray-core/transport/internet/httpupgrade"
"github.com/xtls/xray-core/transport/internet/hysteria" "github.com/xtls/xray-core/transport/internet/hysteria"
"github.com/xtls/xray-core/transport/internet/kcp" "github.com/xtls/xray-core/transport/internet/kcp"
@@ -29,16 +38,6 @@ import (
) )
var ( var (
kcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{
"none": func() interface{} { return new(NoOpAuthenticator) },
"srtp": func() interface{} { return new(SRTPAuthenticator) },
"utp": func() interface{} { return new(UTPAuthenticator) },
"wechat-video": func() interface{} { return new(WechatVideoAuthenticator) },
"dtls": func() interface{} { return new(DTLSAuthenticator) },
"wireguard": func() interface{} { return new(WireguardAuthenticator) },
"dns": func() interface{} { return new(DNSAuthenticator) },
}, "type", "")
tcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{ tcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{
"none": func() interface{} { return new(NoOpConnectionAuthenticator) }, "none": func() interface{} { return new(NoOpConnectionAuthenticator) },
"http": func() interface{} { return new(Authenticator) }, "http": func() interface{} { return new(Authenticator) },
@@ -63,9 +62,9 @@ func (c *KCPConfig) Build() (proto.Message, error) {
if c.Mtu != nil { if c.Mtu != nil {
mtu := *c.Mtu mtu := *c.Mtu
if mtu < 576 || mtu > 1460 { // if mtu < 576 || mtu > 1460 {
return nil, errors.New("invalid mKCP MTU size: ", mtu).AtError() // return nil, errors.New("invalid mKCP MTU size: ", mtu).AtError()
} // }
config.Mtu = &kcp.MTU{Value: mtu} config.Mtu = &kcp.MTU{Value: mtu}
} }
if c.Tti != nil { if c.Tti != nil {
@@ -100,20 +99,8 @@ func (c *KCPConfig) Build() (proto.Message, error) {
config.WriteBuffer = &kcp.WriteBuffer{Size: 512 * 1024} config.WriteBuffer = &kcp.WriteBuffer{Size: 512 * 1024}
} }
} }
if len(c.HeaderConfig) > 0 { if c.HeaderConfig != nil || c.Seed != nil {
headerConfig, _, err := kcpHeaderLoader.Load(c.HeaderConfig) return nil, errors.PrintRemovedFeatureError("mkcp header & seed", "finalmask/udp header-* & mkcp-original & mkcp-aes128gcm")
if err != nil {
return nil, errors.New("invalid mKCP header config.").Base(err).AtError()
}
ts, err := headerConfig.(Buildable).Build()
if err != nil {
return nil, errors.New("invalid mKCP header config").Base(err).AtError()
}
config.HeaderConfig = serial.ToTypedMessage(ts)
}
if c.Seed != nil {
config.Seed = &kcp.EncryptionSeed{Seed: *c.Seed}
} }
return config, nil return config, nil
@@ -1242,10 +1229,80 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
var ( var (
udpmaskLoader = NewJSONConfigLoader(ConfigCreatorCache{ udpmaskLoader = NewJSONConfigLoader(ConfigCreatorCache{
"salamander": func() interface{} { return new(Salamander) }, "header-dns": func() interface{} { return new(Dns) },
"header-dtls": func() interface{} { return new(Dtls) },
"header-srtp": func() interface{} { return new(Srtp) },
"header-utp": func() interface{} { return new(Utp) },
"header-wechat": func() interface{} { return new(Wechat) },
"header-wireguard": func() interface{} { return new(Wireguard) },
"mkcp-original": func() interface{} { return new(Original) },
"mkcp-aes128gcm": func() interface{} { return new(Aes128Gcm) },
"salamander": func() interface{} { return new(Salamander) },
"xdns": func() interface{} { return new(Xdns) },
}, "type", "settings") }, "type", "settings")
) )
type Dns struct {
Domain string `json:"domain"`
}
func (c *Dns) Build() (proto.Message, error) {
config := &dns.Config{}
config.Domain = "www.baidu.com"
if len(c.Domain) > 0 {
config.Domain = c.Domain
}
return config, nil
}
type Dtls struct{}
func (c *Dtls) Build() (proto.Message, error) {
return &dtls.Config{}, nil
}
type Srtp struct{}
func (c *Srtp) Build() (proto.Message, error) {
return &srtp.Config{}, nil
}
type Utp struct{}
func (c *Utp) Build() (proto.Message, error) {
return &utp.Config{}, nil
}
type Wechat struct{}
func (c *Wechat) Build() (proto.Message, error) {
return &wechat.Config{}, nil
}
type Wireguard struct{}
func (c *Wireguard) Build() (proto.Message, error) {
return &wireguard.Config{}, nil
}
type Original struct{}
func (c *Original) Build() (proto.Message, error) {
return &original.Config{}, nil
}
type Aes128Gcm struct {
Password string `json:"password"`
}
func (c *Aes128Gcm) Build() (proto.Message, error) {
return &aes128gcm.Config{
Password: c.Password,
}, nil
}
type Salamander struct { type Salamander struct {
Password string `json:"password"` Password string `json:"password"`
} }
@@ -1256,14 +1313,28 @@ func (c *Salamander) Build() (proto.Message, error) {
return config, nil return config, nil
} }
type FinalMask struct { type Xdns struct {
Domain string `json:"domain"`
}
func (c *Xdns) Build() (proto.Message, error) {
if c.Domain == "" {
return nil, errors.New("empty domain")
}
return &xdns.Config{
Domain: c.Domain,
}, nil
}
type Mask struct {
Type string `json:"type"` Type string `json:"type"`
Settings *json.RawMessage `json:"settings"` Settings *json.RawMessage `json:"settings"`
} }
func (c *FinalMask) Build(tcpmaskLoader bool) (proto.Message, error) { func (c *Mask) Build(tcp bool) (proto.Message, error) {
loader := udpmaskLoader loader := udpmaskLoader
if tcpmaskLoader { if tcp {
return nil, errors.New("") return nil, errors.New("")
} }
@@ -1282,12 +1353,17 @@ func (c *FinalMask) Build(tcpmaskLoader bool) (proto.Message, error) {
return ts, nil return ts, nil
} }
type FinalMask struct {
Tcp []Mask `json:"tcp"`
Udp []Mask `json:"udp"`
}
type StreamConfig struct { type StreamConfig struct {
Address *Address `json:"address"` Address *Address `json:"address"`
Port uint16 `json:"port"` Port uint16 `json:"port"`
Network *TransportProtocol `json:"network"` Network *TransportProtocol `json:"network"`
Security string `json:"security"` Security string `json:"security"`
Udpmasks []*FinalMask `json:"udpmasks"` FinalMask *FinalMask `json:"finalmask"`
TLSSettings *TLSConfig `json:"tlsSettings"` TLSSettings *TLSConfig `json:"tlsSettings"`
REALITYSettings *REALITYConfig `json:"realitySettings"` REALITYSettings *REALITYConfig `json:"realitySettings"`
RAWSettings *TCPConfig `json:"rawSettings"` RAWSettings *TCPConfig `json:"rawSettings"`
@@ -1437,12 +1513,21 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
config.SocketSettings = ss config.SocketSettings = ss
} }
for _, mask := range c.Udpmasks { if c.FinalMask != nil {
u, err := mask.Build(false) for _, mask := range c.FinalMask.Tcp {
if err != nil { u, err := mask.Build(true)
return nil, errors.New("failed to build mask with type ", mask.Type).Base(err) if err != nil {
return nil, errors.New("failed to build mask with type ", mask.Type).Base(err)
}
config.Tcpmasks = append(config.Tcpmasks, serial.ToTypedMessage(u))
}
for _, mask := range c.FinalMask.Udp {
u, err := mask.Build(false)
if err != nil {
return nil, errors.New("failed to build mask with type ", mask.Type).Base(err)
}
config.Udpmasks = append(config.Udpmasks, serial.ToTypedMessage(u))
} }
config.Udpmasks = append(config.Udpmasks, serial.ToTypedMessage(u))
} }
return config, nil return config, nil
-5
View File
@@ -63,11 +63,6 @@ import (
// Transport headers // Transport headers
_ "github.com/xtls/xray-core/transport/internet/headers/http" _ "github.com/xtls/xray-core/transport/internet/headers/http"
_ "github.com/xtls/xray-core/transport/internet/headers/noop" _ "github.com/xtls/xray-core/transport/internet/headers/noop"
_ "github.com/xtls/xray-core/transport/internet/headers/srtp"
_ "github.com/xtls/xray-core/transport/internet/headers/tls"
_ "github.com/xtls/xray-core/transport/internet/headers/utp"
_ "github.com/xtls/xray-core/transport/internet/headers/wechat"
_ "github.com/xtls/xray-core/transport/internet/headers/wireguard"
// JSON & TOML & YAML // JSON & TOML & YAML
_ "github.com/xtls/xray-core/main/json" _ "github.com/xtls/xray-core/main/json"
+14 -50
View File
@@ -4,17 +4,15 @@ import (
"net" "net"
) )
type ConnSize interface {
Size() int32
}
type Udpmask interface { type Udpmask interface {
UDP() UDP()
WrapConnClient(net.Conn) (net.Conn, error) WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error)
WrapConnServer(net.Conn) (net.Conn, error) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error)
WrapPacketConnClient(net.PacketConn) (net.PacketConn, error)
WrapPacketConnServer(net.PacketConn) (net.PacketConn, error)
Size() int
Serialize([]byte)
} }
type UdpmaskManager struct { type UdpmaskManager struct {
@@ -27,66 +25,32 @@ func NewUdpmaskManager(udpmasks []Udpmask) *UdpmaskManager {
} }
} }
func (m *UdpmaskManager) WrapConnClient(raw net.Conn) (net.Conn, error) {
var err error
for _, mask := range m.udpmasks {
raw, err = mask.WrapConnClient(raw)
if err != nil {
return nil, err
}
}
return raw, nil
}
func (m *UdpmaskManager) WrapConnServer(raw net.Conn) (net.Conn, error) {
var err error
for _, mask := range m.udpmasks {
raw, err = mask.WrapConnServer(raw)
if err != nil {
return nil, err
}
}
return raw, nil
}
func (m *UdpmaskManager) WrapPacketConnClient(raw net.PacketConn) (net.PacketConn, error) { func (m *UdpmaskManager) WrapPacketConnClient(raw net.PacketConn) (net.PacketConn, error) {
leaveSize := int32(0)
var err error var err error
for _, mask := range m.udpmasks { for i, mask := range m.udpmasks {
raw, err = mask.WrapPacketConnClient(raw) raw, err = mask.WrapPacketConnClient(raw, i == len(m.udpmasks)-1, leaveSize, i == 0)
if err != nil { if err != nil {
return nil, err return nil, err
} }
leaveSize += raw.(ConnSize).Size()
} }
return raw, nil return raw, nil
} }
func (m *UdpmaskManager) WrapPacketConnServer(raw net.PacketConn) (net.PacketConn, error) { func (m *UdpmaskManager) WrapPacketConnServer(raw net.PacketConn) (net.PacketConn, error) {
leaveSize := int32(0)
var err error var err error
for _, mask := range m.udpmasks { for i, mask := range m.udpmasks {
raw, err = mask.WrapPacketConnServer(raw) raw, err = mask.WrapPacketConnServer(raw, i == len(m.udpmasks)-1, leaveSize, i == 0)
if err != nil { if err != nil {
return nil, err return nil, err
} }
leaveSize += raw.(ConnSize).Size()
} }
return raw, nil return raw, nil
} }
func (m *UdpmaskManager) Size() int {
size := 0
for _, mask := range m.udpmasks {
size += mask.Size()
}
return size
}
func (m *UdpmaskManager) Serialize(b []byte) {
index := 0
for _, mask := range m.udpmasks {
mask.Serialize(b[index:])
index += mask.Size()
}
}
type Tcpmask interface { type Tcpmask interface {
TCP() TCP()
@@ -0,0 +1,16 @@
package dns
import (
"net"
)
func (c *Config) UDP() {
}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnClient(c, raw, first, leaveSize)
}
func (c *Config) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnServer(c, raw, first, leaveSize)
}
@@ -0,0 +1,123 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v6.33.1
// source: transport/internet/finalmask/header/dns/config.proto
package dns
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
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 `protogen:"open.v1"`
Domain string `protobuf:"bytes,1,opt,name=domain,proto3" json:"domain,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Config) Reset() {
*x = Config{}
mi := &file_transport_internet_finalmask_header_dns_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_transport_internet_finalmask_header_dns_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_transport_internet_finalmask_header_dns_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetDomain() string {
if x != nil {
return x.Domain
}
return ""
}
var File_transport_internet_finalmask_header_dns_config_proto protoreflect.FileDescriptor
const file_transport_internet_finalmask_header_dns_config_proto_rawDesc = "" +
"\n" +
"4transport/internet/finalmask/header/dns/config.proto\x12,xray.transport.internet.finalmask.header.dns\" \n" +
"\x06Config\x12\x16\n" +
"\x06domain\x18\x01 \x01(\tR\x06domainB\xa6\x01\n" +
"0com.xray.transport.internet.finalmask.header.dnsP\x01ZAgithub.com/xtls/xray-core/transport/internet/finalmask/header/dns\xaa\x02,Xray.Transport.Internet.Finalmask.Header.Dnsb\x06proto3"
var (
file_transport_internet_finalmask_header_dns_config_proto_rawDescOnce sync.Once
file_transport_internet_finalmask_header_dns_config_proto_rawDescData []byte
)
func file_transport_internet_finalmask_header_dns_config_proto_rawDescGZIP() []byte {
file_transport_internet_finalmask_header_dns_config_proto_rawDescOnce.Do(func() {
file_transport_internet_finalmask_header_dns_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_dns_config_proto_rawDesc), len(file_transport_internet_finalmask_header_dns_config_proto_rawDesc)))
})
return file_transport_internet_finalmask_header_dns_config_proto_rawDescData
}
var file_transport_internet_finalmask_header_dns_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_transport_internet_finalmask_header_dns_config_proto_goTypes = []any{
(*Config)(nil), // 0: xray.transport.internet.finalmask.header.dns.Config
}
var file_transport_internet_finalmask_header_dns_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_transport_internet_finalmask_header_dns_config_proto_init() }
func file_transport_internet_finalmask_header_dns_config_proto_init() {
if File_transport_internet_finalmask_header_dns_config_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_dns_config_proto_rawDesc), len(file_transport_internet_finalmask_header_dns_config_proto_rawDesc)),
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_transport_internet_finalmask_header_dns_config_proto_goTypes,
DependencyIndexes: file_transport_internet_finalmask_header_dns_config_proto_depIdxs,
MessageInfos: file_transport_internet_finalmask_header_dns_config_proto_msgTypes,
}.Build()
File_transport_internet_finalmask_header_dns_config_proto = out.File
file_transport_internet_finalmask_header_dns_config_proto_goTypes = nil
file_transport_internet_finalmask_header_dns_config_proto_depIdxs = nil
}
@@ -0,0 +1,11 @@
syntax = "proto3";
package xray.transport.internet.finalmask.header.dns;
option csharp_namespace = "Xray.Transport.Internet.Finalmask.Header.Dns";
option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/header/dns";
option java_package = "com.xray.transport.internet.finalmask.header.dns";
option java_multiple_files = true;
message Config {
string domain = 1;
}
@@ -0,0 +1,241 @@
package dns
import (
"encoding/binary"
"io"
"net"
sync "sync"
"time"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors"
)
func packDomainName(s string, msg []byte) (off1 int, err error) {
off := 0
ls := len(s)
// Each dot ends a segment of the name.
// We trade each dot byte for a length byte.
// Except for escaped dots (\.), which are normal dots.
// There is also a trailing zero.
// Emit sequence of counted strings, chopping at dots.
var (
begin int
bs []byte
)
for i := 0; i < ls; i++ {
var c byte
if bs == nil {
c = s[i]
} else {
c = bs[i]
}
switch c {
case '\\':
if off+1 > len(msg) {
return len(msg), errors.New("buffer size too small")
}
if bs == nil {
bs = []byte(s)
}
copy(bs[i:ls-1], bs[i+1:])
ls--
case '.':
labelLen := i - begin
if labelLen >= 1<<6 { // top two bits of length must be clear
return len(msg), errors.New("bad rdata")
}
// off can already (we're in a loop) be bigger than len(msg)
// this happens when a name isn't fully qualified
if off+1+labelLen > len(msg) {
return len(msg), errors.New("buffer size too small")
}
// The following is covered by the length check above.
msg[off] = byte(labelLen)
if bs == nil {
copy(msg[off+1:], s[begin:i])
} else {
copy(msg[off+1:], bs[begin:i])
}
off += 1 + labelLen
begin = i + 1
default:
}
}
if off < len(msg) {
msg[off] = 0
}
return off + 1, nil
}
type dns struct {
header []byte
}
func (h *dns) Size() int32 {
return int32(len(h.header))
}
func (h *dns) Serialize(b []byte) {
copy(b, h.header)
binary.BigEndian.PutUint16(b[0:], dice.RollUint16())
}
type dnsConn struct {
first bool
leaveSize int32
conn net.PacketConn
header *dns
readBuf []byte
readMutex sync.Mutex
writeBuf []byte
writeMutex sync.Mutex
}
func NewConnClient(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
var header []byte
header = binary.BigEndian.AppendUint16(header, 0x0000) // Transaction ID
header = binary.BigEndian.AppendUint16(header, 0x0100) // Flags: Standard query
header = binary.BigEndian.AppendUint16(header, 0x0001) // Questions
header = binary.BigEndian.AppendUint16(header, 0x0000) // Answer RRs
header = binary.BigEndian.AppendUint16(header, 0x0000) // Authority RRs
header = binary.BigEndian.AppendUint16(header, 0x0000) // Additional RRs
buf := make([]byte, 0x100)
off1, err := packDomainName(c.Domain+".", buf)
if err != nil {
return nil, err
}
header = append(header, buf[:off1]...)
header = binary.BigEndian.AppendUint16(header, 0x0001) // Type: A
header = binary.BigEndian.AppendUint16(header, 0x0001) // Class: IN
conn := &dnsConn{
first: first,
leaveSize: leaveSize,
conn: raw,
header: &dns{
header: header,
},
}
if first {
conn.readBuf = make([]byte, 8192)
conn.writeBuf = make([]byte, 8192)
}
return conn, nil
}
func NewConnServer(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
return NewConnClient(c, raw, first, leaveSize)
}
func (c *dnsConn) Size() int32 {
return c.header.Size()
}
func (c *dnsConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
if c.first {
c.readMutex.Lock()
n, addr, err = c.conn.ReadFrom(c.readBuf)
if err != nil {
c.readMutex.Unlock()
return n, addr, err
}
if n < int(c.Size()) {
c.readMutex.Unlock()
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
}
if len(p) < n-int(c.Size()) {
c.readMutex.Unlock()
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
}
copy(p, c.readBuf[c.Size():n])
c.readMutex.Unlock()
return n - int(c.Size()), addr, err
}
n, addr, err = c.conn.ReadFrom(p)
if err != nil {
return n, addr, err
}
if n < int(c.Size()) {
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
}
copy(p, p[c.Size():n])
return n - int(c.Size()), addr, err
}
func (c *dnsConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
if c.first {
if c.leaveSize+c.Size()+int32(len(p)) > 8192 {
return 0, errors.New("too many masks")
}
c.writeMutex.Lock()
n = copy(c.writeBuf[c.leaveSize+c.Size():], p)
n += int(c.leaveSize) + int(c.Size())
c.header.Serialize(c.writeBuf[c.leaveSize : c.leaveSize+c.Size()])
nn, err := c.conn.WriteTo(c.writeBuf[:n], addr)
if err != nil {
c.writeMutex.Unlock()
return 0, err
}
if nn != n {
c.writeMutex.Unlock()
return 0, errors.New("nn != n")
}
c.writeMutex.Unlock()
return len(p), nil
}
c.header.Serialize(p[c.leaveSize : c.leaveSize+c.Size()])
return c.conn.WriteTo(p, addr)
}
func (c *dnsConn) Close() error {
return c.conn.Close()
}
func (c *dnsConn) LocalAddr() net.Addr {
return c.conn.LocalAddr()
}
func (c *dnsConn) SetDeadline(t time.Time) error {
return c.conn.SetDeadline(t)
}
func (c *dnsConn) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t)
}
func (c *dnsConn) SetWriteDeadline(t time.Time) error {
return c.conn.SetWriteDeadline(t)
}
@@ -0,0 +1,16 @@
package dtls
import (
"net"
)
func (c *Config) UDP() {
}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnClient(c, raw, first, leaveSize)
}
func (c *Config) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnServer(c, raw, first, leaveSize)
}
@@ -0,0 +1,114 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v6.33.1
// source: transport/internet/finalmask/header/dtls/config.proto
package dtls
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
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 `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Config) Reset() {
*x = Config{}
mi := &file_transport_internet_finalmask_header_dtls_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_transport_internet_finalmask_header_dtls_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_transport_internet_finalmask_header_dtls_config_proto_rawDescGZIP(), []int{0}
}
var File_transport_internet_finalmask_header_dtls_config_proto protoreflect.FileDescriptor
const file_transport_internet_finalmask_header_dtls_config_proto_rawDesc = "" +
"\n" +
"5transport/internet/finalmask/header/dtls/config.proto\x12-xray.transport.internet.finalmask.header.dtls\"\b\n" +
"\x06ConfigB\xa9\x01\n" +
"1com.xray.transport.internet.finalmask.header.dtlsP\x01ZBgithub.com/xtls/xray-core/transport/internet/finalmask/header/dtls\xaa\x02-Xray.Transport.Internet.Finalmask.Header.Dtlsb\x06proto3"
var (
file_transport_internet_finalmask_header_dtls_config_proto_rawDescOnce sync.Once
file_transport_internet_finalmask_header_dtls_config_proto_rawDescData []byte
)
func file_transport_internet_finalmask_header_dtls_config_proto_rawDescGZIP() []byte {
file_transport_internet_finalmask_header_dtls_config_proto_rawDescOnce.Do(func() {
file_transport_internet_finalmask_header_dtls_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_dtls_config_proto_rawDesc), len(file_transport_internet_finalmask_header_dtls_config_proto_rawDesc)))
})
return file_transport_internet_finalmask_header_dtls_config_proto_rawDescData
}
var file_transport_internet_finalmask_header_dtls_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_transport_internet_finalmask_header_dtls_config_proto_goTypes = []any{
(*Config)(nil), // 0: xray.transport.internet.finalmask.header.dtls.Config
}
var file_transport_internet_finalmask_header_dtls_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_transport_internet_finalmask_header_dtls_config_proto_init() }
func file_transport_internet_finalmask_header_dtls_config_proto_init() {
if File_transport_internet_finalmask_header_dtls_config_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_dtls_config_proto_rawDesc), len(file_transport_internet_finalmask_header_dtls_config_proto_rawDesc)),
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_transport_internet_finalmask_header_dtls_config_proto_goTypes,
DependencyIndexes: file_transport_internet_finalmask_header_dtls_config_proto_depIdxs,
MessageInfos: file_transport_internet_finalmask_header_dtls_config_proto_msgTypes,
}.Build()
File_transport_internet_finalmask_header_dtls_config_proto = out.File
file_transport_internet_finalmask_header_dtls_config_proto_goTypes = nil
file_transport_internet_finalmask_header_dtls_config_proto_depIdxs = nil
}
@@ -0,0 +1,9 @@
syntax = "proto3";
package xray.transport.internet.finalmask.header.dtls;
option csharp_namespace = "Xray.Transport.Internet.Finalmask.Header.Dtls";
option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/header/dtls";
option java_package = "com.xray.transport.internet.finalmask.header.dtls";
option java_multiple_files = true;
message Config {}
@@ -0,0 +1,178 @@
package dtls
import (
"io"
"net"
sync "sync"
"time"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors"
)
type dtls struct {
epoch uint16
length uint16
sequence uint32
}
func (*dtls) Size() int32 {
return 1 + 2 + 2 + 6 + 2
}
func (h *dtls) Serialize(b []byte) {
b[0] = 23
b[1] = 254
b[2] = 253
b[3] = byte(h.epoch >> 8)
b[4] = byte(h.epoch)
b[5] = 0
b[6] = 0
b[7] = byte(h.sequence >> 24)
b[8] = byte(h.sequence >> 16)
b[9] = byte(h.sequence >> 8)
b[10] = byte(h.sequence)
h.sequence++
b[11] = byte(h.length >> 8)
b[12] = byte(h.length)
h.length += 17
if h.length > 100 {
h.length -= 50
}
}
type dtlsConn struct {
first bool
leaveSize int32
conn net.PacketConn
header *dtls
readBuf []byte
readMutex sync.Mutex
writeBuf []byte
writeMutex sync.Mutex
}
func NewConnClient(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
conn := &dtlsConn{
first: first,
leaveSize: leaveSize,
conn: raw,
header: &dtls{
epoch: dice.RollUint16(),
sequence: 0,
length: 17,
},
}
if first {
conn.readBuf = make([]byte, 8192)
conn.writeBuf = make([]byte, 8192)
}
return conn, nil
}
func NewConnServer(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
return NewConnClient(c, raw, first, leaveSize)
}
func (c *dtlsConn) Size() int32 {
return c.header.Size()
}
func (c *dtlsConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
if c.first {
c.readMutex.Lock()
n, addr, err = c.conn.ReadFrom(c.readBuf)
if err != nil {
c.readMutex.Unlock()
return n, addr, err
}
if n < int(c.Size()) {
c.readMutex.Unlock()
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
}
if len(p) < n-int(c.Size()) {
c.readMutex.Unlock()
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
}
copy(p, c.readBuf[c.Size():n])
c.readMutex.Unlock()
return n - int(c.Size()), addr, err
}
n, addr, err = c.conn.ReadFrom(p)
if err != nil {
return n, addr, err
}
if n < int(c.Size()) {
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
}
copy(p, p[c.Size():n])
return n - int(c.Size()), addr, err
}
func (c *dtlsConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
if c.first {
if c.leaveSize+c.Size()+int32(len(p)) > 8192 {
return 0, errors.New("too many masks")
}
c.writeMutex.Lock()
n = copy(c.writeBuf[c.leaveSize+c.Size():], p)
n += int(c.leaveSize) + int(c.Size())
c.header.Serialize(c.writeBuf[c.leaveSize : c.leaveSize+c.Size()])
nn, err := c.conn.WriteTo(c.writeBuf[:n], addr)
if err != nil {
c.writeMutex.Unlock()
return 0, err
}
if nn != n {
c.writeMutex.Unlock()
return 0, errors.New("nn != n")
}
c.writeMutex.Unlock()
return len(p), nil
}
c.header.Serialize(p[c.leaveSize : c.leaveSize+c.Size()])
return c.conn.WriteTo(p, addr)
}
func (c *dtlsConn) Close() error {
return c.conn.Close()
}
func (c *dtlsConn) LocalAddr() net.Addr {
return c.conn.LocalAddr()
}
func (c *dtlsConn) SetDeadline(t time.Time) error {
return c.conn.SetDeadline(t)
}
func (c *dtlsConn) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t)
}
func (c *dtlsConn) SetWriteDeadline(t time.Time) error {
return c.conn.SetWriteDeadline(t)
}
@@ -0,0 +1,16 @@
package srtp
import (
"net"
)
func (c *Config) UDP() {
}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnClient(c, raw, first, leaveSize)
}
func (c *Config) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnServer(c, raw, first, leaveSize)
}
@@ -0,0 +1,114 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v6.33.1
// source: transport/internet/finalmask/header/srtp/config.proto
package srtp
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
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 `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Config) Reset() {
*x = Config{}
mi := &file_transport_internet_finalmask_header_srtp_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_transport_internet_finalmask_header_srtp_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_transport_internet_finalmask_header_srtp_config_proto_rawDescGZIP(), []int{0}
}
var File_transport_internet_finalmask_header_srtp_config_proto protoreflect.FileDescriptor
const file_transport_internet_finalmask_header_srtp_config_proto_rawDesc = "" +
"\n" +
"5transport/internet/finalmask/header/srtp/config.proto\x12-xray.transport.internet.finalmask.header.srtp\"\b\n" +
"\x06ConfigB\xa9\x01\n" +
"1com.xray.transport.internet.finalmask.header.srtpP\x01ZBgithub.com/xtls/xray-core/transport/internet/finalmask/header/srtp\xaa\x02-Xray.Transport.Internet.Finalmask.Header.Srtpb\x06proto3"
var (
file_transport_internet_finalmask_header_srtp_config_proto_rawDescOnce sync.Once
file_transport_internet_finalmask_header_srtp_config_proto_rawDescData []byte
)
func file_transport_internet_finalmask_header_srtp_config_proto_rawDescGZIP() []byte {
file_transport_internet_finalmask_header_srtp_config_proto_rawDescOnce.Do(func() {
file_transport_internet_finalmask_header_srtp_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_srtp_config_proto_rawDesc), len(file_transport_internet_finalmask_header_srtp_config_proto_rawDesc)))
})
return file_transport_internet_finalmask_header_srtp_config_proto_rawDescData
}
var file_transport_internet_finalmask_header_srtp_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_transport_internet_finalmask_header_srtp_config_proto_goTypes = []any{
(*Config)(nil), // 0: xray.transport.internet.finalmask.header.srtp.Config
}
var file_transport_internet_finalmask_header_srtp_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_transport_internet_finalmask_header_srtp_config_proto_init() }
func file_transport_internet_finalmask_header_srtp_config_proto_init() {
if File_transport_internet_finalmask_header_srtp_config_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_srtp_config_proto_rawDesc), len(file_transport_internet_finalmask_header_srtp_config_proto_rawDesc)),
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_transport_internet_finalmask_header_srtp_config_proto_goTypes,
DependencyIndexes: file_transport_internet_finalmask_header_srtp_config_proto_depIdxs,
MessageInfos: file_transport_internet_finalmask_header_srtp_config_proto_msgTypes,
}.Build()
File_transport_internet_finalmask_header_srtp_config_proto = out.File
file_transport_internet_finalmask_header_srtp_config_proto_goTypes = nil
file_transport_internet_finalmask_header_srtp_config_proto_depIdxs = nil
}
@@ -0,0 +1,9 @@
syntax = "proto3";
package xray.transport.internet.finalmask.header.srtp;
option csharp_namespace = "Xray.Transport.Internet.Finalmask.Header.Srtp";
option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/header/srtp";
option java_package = "com.xray.transport.internet.finalmask.header.srtp";
option java_multiple_files = true;
message Config {}
@@ -0,0 +1,162 @@
package srtp
import (
"encoding/binary"
"io"
"net"
sync "sync"
"time"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors"
)
type srtp struct {
header uint16
number uint16
}
func (*srtp) Size() int32 {
return 4
}
func (h *srtp) Serialize(b []byte) {
h.number++
binary.BigEndian.PutUint16(b, h.header)
binary.BigEndian.PutUint16(b[2:], h.number)
}
type srtpConn struct {
first bool
leaveSize int32
conn net.PacketConn
header *srtp
readBuf []byte
readMutex sync.Mutex
writeBuf []byte
writeMutex sync.Mutex
}
func NewConnClient(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
conn := &srtpConn{
first: first,
leaveSize: leaveSize,
conn: raw,
header: &srtp{
header: 0xB5E8,
number: dice.RollUint16(),
},
}
if first {
conn.readBuf = make([]byte, 8192)
conn.writeBuf = make([]byte, 8192)
}
return conn, nil
}
func NewConnServer(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
return NewConnClient(c, raw, first, leaveSize)
}
func (c *srtpConn) Size() int32 {
return c.header.Size()
}
func (c *srtpConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
if c.first {
c.readMutex.Lock()
n, addr, err = c.conn.ReadFrom(c.readBuf)
if err != nil {
c.readMutex.Unlock()
return n, addr, err
}
if n < int(c.Size()) {
c.readMutex.Unlock()
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
}
if len(p) < n-int(c.Size()) {
c.readMutex.Unlock()
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
}
copy(p, c.readBuf[c.Size():n])
c.readMutex.Unlock()
return n - int(c.Size()), addr, err
}
n, addr, err = c.conn.ReadFrom(p)
if err != nil {
return n, addr, err
}
if n < int(c.Size()) {
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
}
copy(p, p[c.Size():n])
return n - int(c.Size()), addr, err
}
func (c *srtpConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
if c.first {
if c.leaveSize+c.Size()+int32(len(p)) > 8192 {
return 0, errors.New("too many masks")
}
c.writeMutex.Lock()
n = copy(c.writeBuf[c.leaveSize+c.Size():], p)
n += int(c.leaveSize) + int(c.Size())
c.header.Serialize(c.writeBuf[c.leaveSize : c.leaveSize+c.Size()])
nn, err := c.conn.WriteTo(c.writeBuf[:n], addr)
if err != nil {
c.writeMutex.Unlock()
return 0, err
}
if nn != n {
c.writeMutex.Unlock()
return 0, errors.New("nn != n")
}
c.writeMutex.Unlock()
return len(p), nil
}
c.header.Serialize(p[c.leaveSize : c.leaveSize+c.Size()])
return c.conn.WriteTo(p, addr)
}
func (c *srtpConn) Close() error {
return c.conn.Close()
}
func (c *srtpConn) LocalAddr() net.Addr {
return c.conn.LocalAddr()
}
func (c *srtpConn) SetDeadline(t time.Time) error {
return c.conn.SetDeadline(t)
}
func (c *srtpConn) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t)
}
func (c *srtpConn) SetWriteDeadline(t time.Time) error {
return c.conn.SetWriteDeadline(t)
}
@@ -0,0 +1,16 @@
package utp
import (
"net"
)
func (c *Config) UDP() {
}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnClient(c, raw, first, leaveSize)
}
func (c *Config) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnServer(c, raw, first, leaveSize)
}
@@ -0,0 +1,114 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v6.33.1
// source: transport/internet/finalmask/header/utp/config.proto
package utp
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
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 `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Config) Reset() {
*x = Config{}
mi := &file_transport_internet_finalmask_header_utp_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_transport_internet_finalmask_header_utp_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_transport_internet_finalmask_header_utp_config_proto_rawDescGZIP(), []int{0}
}
var File_transport_internet_finalmask_header_utp_config_proto protoreflect.FileDescriptor
const file_transport_internet_finalmask_header_utp_config_proto_rawDesc = "" +
"\n" +
"4transport/internet/finalmask/header/utp/config.proto\x12,xray.transport.internet.finalmask.header.utp\"\b\n" +
"\x06ConfigB\xa6\x01\n" +
"0com.xray.transport.internet.finalmask.header.utpP\x01ZAgithub.com/xtls/xray-core/transport/internet/finalmask/header/utp\xaa\x02,Xray.Transport.Internet.Finalmask.Header.Utpb\x06proto3"
var (
file_transport_internet_finalmask_header_utp_config_proto_rawDescOnce sync.Once
file_transport_internet_finalmask_header_utp_config_proto_rawDescData []byte
)
func file_transport_internet_finalmask_header_utp_config_proto_rawDescGZIP() []byte {
file_transport_internet_finalmask_header_utp_config_proto_rawDescOnce.Do(func() {
file_transport_internet_finalmask_header_utp_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_utp_config_proto_rawDesc), len(file_transport_internet_finalmask_header_utp_config_proto_rawDesc)))
})
return file_transport_internet_finalmask_header_utp_config_proto_rawDescData
}
var file_transport_internet_finalmask_header_utp_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_transport_internet_finalmask_header_utp_config_proto_goTypes = []any{
(*Config)(nil), // 0: xray.transport.internet.finalmask.header.utp.Config
}
var file_transport_internet_finalmask_header_utp_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_transport_internet_finalmask_header_utp_config_proto_init() }
func file_transport_internet_finalmask_header_utp_config_proto_init() {
if File_transport_internet_finalmask_header_utp_config_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_utp_config_proto_rawDesc), len(file_transport_internet_finalmask_header_utp_config_proto_rawDesc)),
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_transport_internet_finalmask_header_utp_config_proto_goTypes,
DependencyIndexes: file_transport_internet_finalmask_header_utp_config_proto_depIdxs,
MessageInfos: file_transport_internet_finalmask_header_utp_config_proto_msgTypes,
}.Build()
File_transport_internet_finalmask_header_utp_config_proto = out.File
file_transport_internet_finalmask_header_utp_config_proto_goTypes = nil
file_transport_internet_finalmask_header_utp_config_proto_depIdxs = nil
}
@@ -0,0 +1,9 @@
syntax = "proto3";
package xray.transport.internet.finalmask.header.utp;
option csharp_namespace = "Xray.Transport.Internet.Finalmask.Header.Utp";
option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/header/utp";
option java_package = "com.xray.transport.internet.finalmask.header.utp";
option java_multiple_files = true;
message Config {}
@@ -0,0 +1,164 @@
package utp
import (
"encoding/binary"
"io"
"net"
sync "sync"
"time"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors"
)
type utp struct {
header byte
extension byte
connectionID uint16
}
func (*utp) Size() int32 {
return 4
}
func (h *utp) Serialize(b []byte) {
binary.BigEndian.PutUint16(b, h.connectionID)
b[2] = h.header
b[3] = h.extension
}
type utpConn struct {
first bool
leaveSize int32
conn net.PacketConn
header *utp
readBuf []byte
readMutex sync.Mutex
writeBuf []byte
writeMutex sync.Mutex
}
func NewConnClient(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
conn := &utpConn{
first: first,
leaveSize: leaveSize,
conn: raw,
header: &utp{
header: 1,
extension: 0,
connectionID: dice.RollUint16(),
},
}
if first {
conn.readBuf = make([]byte, 8192)
conn.writeBuf = make([]byte, 8192)
}
return conn, nil
}
func NewConnServer(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
return NewConnClient(c, raw, first, leaveSize)
}
func (c *utpConn) Size() int32 {
return c.header.Size()
}
func (c *utpConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
if c.first {
c.readMutex.Lock()
n, addr, err = c.conn.ReadFrom(c.readBuf)
if err != nil {
c.readMutex.Unlock()
return n, addr, err
}
if n < int(c.Size()) {
c.readMutex.Unlock()
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
}
if len(p) < n-int(c.Size()) {
c.readMutex.Unlock()
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
}
copy(p, c.readBuf[c.Size():n])
c.readMutex.Unlock()
return n - int(c.Size()), addr, err
}
n, addr, err = c.conn.ReadFrom(p)
if err != nil {
return n, addr, err
}
if n < int(c.Size()) {
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
}
copy(p, p[c.Size():n])
return n - int(c.Size()), addr, err
}
func (c *utpConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
if c.first {
if c.leaveSize+c.Size()+int32(len(p)) > 8192 {
return 0, errors.New("too many masks")
}
c.writeMutex.Lock()
n = copy(c.writeBuf[c.leaveSize+c.Size():], p)
n += int(c.leaveSize) + int(c.Size())
c.header.Serialize(c.writeBuf[c.leaveSize : c.leaveSize+c.Size()])
nn, err := c.conn.WriteTo(c.writeBuf[:n], addr)
if err != nil {
c.writeMutex.Unlock()
return 0, err
}
if nn != n {
c.writeMutex.Unlock()
return 0, errors.New("nn != n")
}
c.writeMutex.Unlock()
return len(p), nil
}
c.header.Serialize(p[c.leaveSize : c.leaveSize+c.Size()])
return c.conn.WriteTo(p, addr)
}
func (c *utpConn) Close() error {
return c.conn.Close()
}
func (c *utpConn) LocalAddr() net.Addr {
return c.conn.LocalAddr()
}
func (c *utpConn) SetDeadline(t time.Time) error {
return c.conn.SetDeadline(t)
}
func (c *utpConn) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t)
}
func (c *utpConn) SetWriteDeadline(t time.Time) error {
return c.conn.SetWriteDeadline(t)
}
@@ -0,0 +1,16 @@
package wechat
import (
"net"
)
func (c *Config) UDP() {
}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnClient(c, raw, first, leaveSize)
}
func (c *Config) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnServer(c, raw, first, leaveSize)
}
@@ -0,0 +1,114 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v6.33.1
// source: transport/internet/finalmask/header/wechat/config.proto
package wechat
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
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 `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Config) Reset() {
*x = Config{}
mi := &file_transport_internet_finalmask_header_wechat_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_transport_internet_finalmask_header_wechat_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_transport_internet_finalmask_header_wechat_config_proto_rawDescGZIP(), []int{0}
}
var File_transport_internet_finalmask_header_wechat_config_proto protoreflect.FileDescriptor
const file_transport_internet_finalmask_header_wechat_config_proto_rawDesc = "" +
"\n" +
"7transport/internet/finalmask/header/wechat/config.proto\x12/xray.transport.internet.finalmask.header.wechat\"\b\n" +
"\x06ConfigB\xaf\x01\n" +
"3com.xray.transport.internet.finalmask.header.wechatP\x01ZDgithub.com/xtls/xray-core/transport/internet/finalmask/header/wechat\xaa\x02/Xray.Transport.Internet.Finalmask.Header.Wechatb\x06proto3"
var (
file_transport_internet_finalmask_header_wechat_config_proto_rawDescOnce sync.Once
file_transport_internet_finalmask_header_wechat_config_proto_rawDescData []byte
)
func file_transport_internet_finalmask_header_wechat_config_proto_rawDescGZIP() []byte {
file_transport_internet_finalmask_header_wechat_config_proto_rawDescOnce.Do(func() {
file_transport_internet_finalmask_header_wechat_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_wechat_config_proto_rawDesc), len(file_transport_internet_finalmask_header_wechat_config_proto_rawDesc)))
})
return file_transport_internet_finalmask_header_wechat_config_proto_rawDescData
}
var file_transport_internet_finalmask_header_wechat_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_transport_internet_finalmask_header_wechat_config_proto_goTypes = []any{
(*Config)(nil), // 0: xray.transport.internet.finalmask.header.wechat.Config
}
var file_transport_internet_finalmask_header_wechat_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_transport_internet_finalmask_header_wechat_config_proto_init() }
func file_transport_internet_finalmask_header_wechat_config_proto_init() {
if File_transport_internet_finalmask_header_wechat_config_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_wechat_config_proto_rawDesc), len(file_transport_internet_finalmask_header_wechat_config_proto_rawDesc)),
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_transport_internet_finalmask_header_wechat_config_proto_goTypes,
DependencyIndexes: file_transport_internet_finalmask_header_wechat_config_proto_depIdxs,
MessageInfos: file_transport_internet_finalmask_header_wechat_config_proto_msgTypes,
}.Build()
File_transport_internet_finalmask_header_wechat_config_proto = out.File
file_transport_internet_finalmask_header_wechat_config_proto_goTypes = nil
file_transport_internet_finalmask_header_wechat_config_proto_depIdxs = nil
}
@@ -0,0 +1,9 @@
syntax = "proto3";
package xray.transport.internet.finalmask.header.wechat;
option csharp_namespace = "Xray.Transport.Internet.Finalmask.Header.Wechat";
option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/header/wechat";
option java_package = "com.xray.transport.internet.finalmask.header.wechat";
option java_multiple_files = true;
message Config {}
@@ -0,0 +1,168 @@
package wechat
import (
"encoding/binary"
"io"
"net"
sync "sync"
"time"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors"
)
type wechat struct {
sn uint32
}
func (*wechat) Size() int32 {
return 13
}
func (h *wechat) Serialize(b []byte) {
h.sn++
b[0] = 0xa1
b[1] = 0x08
binary.BigEndian.PutUint32(b[2:], h.sn)
b[6] = 0x00
b[7] = 0x10
b[8] = 0x11
b[9] = 0x18
b[10] = 0x30
b[11] = 0x22
b[12] = 0x30
}
type wechatConn struct {
first bool
leaveSize int32
conn net.PacketConn
header *wechat
readBuf []byte
readMutex sync.Mutex
writeBuf []byte
writeMutex sync.Mutex
}
func NewConnClient(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
conn := &wechatConn{
first: first,
leaveSize: leaveSize,
conn: raw,
header: &wechat{
sn: uint32(dice.RollUint16()),
},
}
if first {
conn.readBuf = make([]byte, 8192)
conn.writeBuf = make([]byte, 8192)
}
return conn, nil
}
func NewConnServer(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
return NewConnClient(c, raw, first, leaveSize)
}
func (c *wechatConn) Size() int32 {
return c.header.Size()
}
func (c *wechatConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
if c.first {
c.readMutex.Lock()
n, addr, err = c.conn.ReadFrom(c.readBuf)
if err != nil {
c.readMutex.Unlock()
return n, addr, err
}
if n < int(c.Size()) {
c.readMutex.Unlock()
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
}
if len(p) < n-int(c.Size()) {
c.readMutex.Unlock()
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
}
copy(p, c.readBuf[c.Size():n])
c.readMutex.Unlock()
return n - int(c.Size()), addr, err
}
n, addr, err = c.conn.ReadFrom(p)
if err != nil {
return n, addr, err
}
if n < int(c.Size()) {
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
}
copy(p, p[c.Size():n])
return n - int(c.Size()), addr, err
}
func (c *wechatConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
if c.first {
if c.leaveSize+c.Size()+int32(len(p)) > 8192 {
return 0, errors.New("too many masks")
}
c.writeMutex.Lock()
n = copy(c.writeBuf[c.leaveSize+c.Size():], p)
n += int(c.leaveSize) + int(c.Size())
c.header.Serialize(c.writeBuf[c.leaveSize : c.leaveSize+c.Size()])
nn, err := c.conn.WriteTo(c.writeBuf[:n], addr)
if err != nil {
c.writeMutex.Unlock()
return 0, err
}
if nn != n {
c.writeMutex.Unlock()
return 0, errors.New("nn != n")
}
c.writeMutex.Unlock()
return len(p), nil
}
c.header.Serialize(p[c.leaveSize : c.leaveSize+c.Size()])
return c.conn.WriteTo(p, addr)
}
func (c *wechatConn) Close() error {
return c.conn.Close()
}
func (c *wechatConn) LocalAddr() net.Addr {
return c.conn.LocalAddr()
}
func (c *wechatConn) SetDeadline(t time.Time) error {
return c.conn.SetDeadline(t)
}
func (c *wechatConn) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t)
}
func (c *wechatConn) SetWriteDeadline(t time.Time) error {
return c.conn.SetWriteDeadline(t)
}
@@ -0,0 +1,16 @@
package wireguard
import (
"net"
)
func (c *Config) UDP() {
}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnClient(c, raw, first, leaveSize)
}
func (c *Config) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnServer(c, raw, first, leaveSize)
}
@@ -0,0 +1,114 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v6.33.1
// source: transport/internet/finalmask/header/wireguard/config.proto
package wireguard
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
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 `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Config) Reset() {
*x = Config{}
mi := &file_transport_internet_finalmask_header_wireguard_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_transport_internet_finalmask_header_wireguard_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_transport_internet_finalmask_header_wireguard_config_proto_rawDescGZIP(), []int{0}
}
var File_transport_internet_finalmask_header_wireguard_config_proto protoreflect.FileDescriptor
const file_transport_internet_finalmask_header_wireguard_config_proto_rawDesc = "" +
"\n" +
":transport/internet/finalmask/header/wireguard/config.proto\x122xray.transport.internet.finalmask.header.wireguard\"\b\n" +
"\x06ConfigB\xb8\x01\n" +
"6com.xray.transport.internet.finalmask.header.wireguardP\x01ZGgithub.com/xtls/xray-core/transport/internet/finalmask/header/wireguard\xaa\x022Xray.Transport.Internet.Finalmask.Header.Wireguardb\x06proto3"
var (
file_transport_internet_finalmask_header_wireguard_config_proto_rawDescOnce sync.Once
file_transport_internet_finalmask_header_wireguard_config_proto_rawDescData []byte
)
func file_transport_internet_finalmask_header_wireguard_config_proto_rawDescGZIP() []byte {
file_transport_internet_finalmask_header_wireguard_config_proto_rawDescOnce.Do(func() {
file_transport_internet_finalmask_header_wireguard_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_wireguard_config_proto_rawDesc), len(file_transport_internet_finalmask_header_wireguard_config_proto_rawDesc)))
})
return file_transport_internet_finalmask_header_wireguard_config_proto_rawDescData
}
var file_transport_internet_finalmask_header_wireguard_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_transport_internet_finalmask_header_wireguard_config_proto_goTypes = []any{
(*Config)(nil), // 0: xray.transport.internet.finalmask.header.wireguard.Config
}
var file_transport_internet_finalmask_header_wireguard_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_transport_internet_finalmask_header_wireguard_config_proto_init() }
func file_transport_internet_finalmask_header_wireguard_config_proto_init() {
if File_transport_internet_finalmask_header_wireguard_config_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_header_wireguard_config_proto_rawDesc), len(file_transport_internet_finalmask_header_wireguard_config_proto_rawDesc)),
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_transport_internet_finalmask_header_wireguard_config_proto_goTypes,
DependencyIndexes: file_transport_internet_finalmask_header_wireguard_config_proto_depIdxs,
MessageInfos: file_transport_internet_finalmask_header_wireguard_config_proto_msgTypes,
}.Build()
File_transport_internet_finalmask_header_wireguard_config_proto = out.File
file_transport_internet_finalmask_header_wireguard_config_proto_goTypes = nil
file_transport_internet_finalmask_header_wireguard_config_proto_depIdxs = nil
}
@@ -0,0 +1,9 @@
syntax = "proto3";
package xray.transport.internet.finalmask.header.wireguard;
option csharp_namespace = "Xray.Transport.Internet.Finalmask.Header.Wireguard";
option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/header/wireguard";
option java_package = "com.xray.transport.internet.finalmask.header.wireguard";
option java_multiple_files = true;
message Config {}
@@ -0,0 +1,155 @@
package wireguard
import (
"io"
"net"
sync "sync"
"time"
"github.com/xtls/xray-core/common/errors"
)
type wireguare struct{}
func (*wireguare) Size() int32 {
return 4
}
func (h *wireguare) Serialize(b []byte) {
b[0] = 0x04
b[1] = 0x00
b[2] = 0x00
b[3] = 0x00
}
type wireguareConn struct {
first bool
leaveSize int32
conn net.PacketConn
header *wireguare
readBuf []byte
readMutex sync.Mutex
writeBuf []byte
writeMutex sync.Mutex
}
func NewConnClient(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
conn := &wireguareConn{
first: first,
leaveSize: leaveSize,
conn: raw,
header: &wireguare{},
}
if first {
conn.readBuf = make([]byte, 8192)
conn.writeBuf = make([]byte, 8192)
}
return conn, nil
}
func NewConnServer(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
return NewConnClient(c, raw, first, leaveSize)
}
func (c *wireguareConn) Size() int32 {
return c.header.Size()
}
func (c *wireguareConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
if c.first {
c.readMutex.Lock()
n, addr, err = c.conn.ReadFrom(c.readBuf)
if err != nil {
c.readMutex.Unlock()
return n, addr, err
}
if n < int(c.Size()) {
c.readMutex.Unlock()
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
}
if len(p) < n-int(c.Size()) {
c.readMutex.Unlock()
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
}
copy(p, c.readBuf[c.Size():n])
c.readMutex.Unlock()
return n - int(c.Size()), addr, err
}
n, addr, err = c.conn.ReadFrom(p)
if err != nil {
return n, addr, err
}
if n < int(c.Size()) {
return 0, addr, errors.New("header").Base(io.ErrShortBuffer)
}
copy(p, p[c.Size():n])
return n - int(c.Size()), addr, err
}
func (c *wireguareConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
if c.first {
if c.leaveSize+c.Size()+int32(len(p)) > 8192 {
return 0, errors.New("too many masks")
}
c.writeMutex.Lock()
n = copy(c.writeBuf[c.leaveSize+c.Size():], p)
n += int(c.leaveSize) + int(c.Size())
c.header.Serialize(c.writeBuf[c.leaveSize : c.leaveSize+c.Size()])
nn, err := c.conn.WriteTo(c.writeBuf[:n], addr)
if err != nil {
c.writeMutex.Unlock()
return 0, err
}
if nn != n {
c.writeMutex.Unlock()
return 0, errors.New("nn != n")
}
c.writeMutex.Unlock()
return len(p), nil
}
c.header.Serialize(p[c.leaveSize : c.leaveSize+c.Size()])
return c.conn.WriteTo(p, addr)
}
func (c *wireguareConn) Close() error {
return c.conn.Close()
}
func (c *wireguareConn) LocalAddr() net.Addr {
return c.conn.LocalAddr()
}
func (c *wireguareConn) SetDeadline(t time.Time) error {
return c.conn.SetDeadline(t)
}
func (c *wireguareConn) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t)
}
func (c *wireguareConn) SetWriteDeadline(t time.Time) error {
return c.conn.SetWriteDeadline(t)
}
@@ -0,0 +1,70 @@
package aes128gcm_test
import (
"crypto/rand"
"crypto/sha256"
"testing"
"github.com/stretchr/testify/assert"
"github.com/xtls/xray-core/common/crypto"
)
func TestAes128GcmSealInPlace(t *testing.T) {
hashedPsk := sha256.Sum256([]byte("psk"))
aead := crypto.NewAesGcm(hashedPsk[:16])
text := []byte("0123456789012")
buf := make([]byte, 8192)
nonceSize := aead.NonceSize()
nonce := buf[:nonceSize]
rand.Read(nonce)
copy(buf[nonceSize:], text)
plaintext := buf[nonceSize : nonceSize+len(text)]
sealed := aead.Seal(nil, nonce, plaintext, nil)
_ = aead.Seal(plaintext[:0], nonce, plaintext, nil)
assert.Equal(t, sealed, buf[nonceSize:nonceSize+aead.Overhead()+len(text)])
}
func encrypted(plain []byte) ([]byte, []byte) {
hashedPsk := sha256.Sum256([]byte("psk"))
aead := crypto.NewAesGcm(hashedPsk[:16])
nonce := make([]byte, 12)
rand.Read(nonce)
return nonce, aead.Seal(nil, nonce, plain, nil)
}
func TestAes128GcmOpenInPlace(t *testing.T) {
a, b := encrypted([]byte("0123456789012"))
buf := make([]byte, 8192)
copy(buf, a)
copy(buf[len(a):], b)
hashedPsk := sha256.Sum256([]byte("psk"))
aead := crypto.NewAesGcm(hashedPsk[:16])
nonceSize := aead.NonceSize()
nonce := buf[:nonceSize]
ciphertext := buf[nonceSize : nonceSize+len(b)]
opened, _ := aead.Open(nil, nonce, ciphertext, nil)
_, _ = aead.Open(ciphertext[:0], nonce, ciphertext, nil)
assert.Equal(t, opened, ciphertext[:len(ciphertext)-aead.Overhead()])
}
func TestAes128GcmBounce(t *testing.T) {
hashedPsk := sha256.Sum256([]byte("psk"))
aead := crypto.NewAesGcm(hashedPsk[:16])
buf := make([]byte, aead.NonceSize()+aead.Overhead())
for i := 0; i < 1000; i++ {
_, _ = rand.Read(buf)
_, err := aead.Open(buf[aead.NonceSize():aead.NonceSize()], buf[:aead.NonceSize()], buf[aead.NonceSize():], nil)
assert.NotEqual(t, err, nil)
}
}
@@ -0,0 +1,16 @@
package aes128gcm
import (
"net"
)
func (c *Config) UDP() {
}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnClient(c, raw, first, leaveSize)
}
func (c *Config) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnServer(c, raw, first, leaveSize)
}
@@ -0,0 +1,123 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v6.33.1
// source: transport/internet/finalmask/mkcp/aes128gcm/config.proto
package aes128gcm
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
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 `protogen:"open.v1"`
Password string `protobuf:"bytes,1,opt,name=password,proto3" json:"password,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Config) Reset() {
*x = Config{}
mi := &file_transport_internet_finalmask_mkcp_aes128gcm_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_transport_internet_finalmask_mkcp_aes128gcm_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_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetPassword() string {
if x != nil {
return x.Password
}
return ""
}
var File_transport_internet_finalmask_mkcp_aes128gcm_config_proto protoreflect.FileDescriptor
const file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDesc = "" +
"\n" +
"8transport/internet/finalmask/mkcp/aes128gcm/config.proto\x120xray.transport.internet.finalmask.mkcp.aes128gcm\"$\n" +
"\x06Config\x12\x1a\n" +
"\bpassword\x18\x01 \x01(\tR\bpasswordB\xb2\x01\n" +
"4com.xray.transport.internet.finalmask.mkcp.aes128gcmP\x01ZEgithub.com/xtls/xray-core/transport/internet/finalmask/mkcp/aes128gcm\xaa\x020Xray.Transport.Internet.Finalmask.Mkcp.Aes128Gcmb\x06proto3"
var (
file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDescOnce sync.Once
file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDescData []byte
)
func file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDescGZIP() []byte {
file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDescOnce.Do(func() {
file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDesc), len(file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDesc)))
})
return file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDescData
}
var file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_goTypes = []any{
(*Config)(nil), // 0: xray.transport.internet.finalmask.mkcp.aes128gcm.Config
}
var file_transport_internet_finalmask_mkcp_aes128gcm_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_transport_internet_finalmask_mkcp_aes128gcm_config_proto_init() }
func file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_init() {
if File_transport_internet_finalmask_mkcp_aes128gcm_config_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDesc), len(file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_rawDesc)),
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_goTypes,
DependencyIndexes: file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_depIdxs,
MessageInfos: file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_msgTypes,
}.Build()
File_transport_internet_finalmask_mkcp_aes128gcm_config_proto = out.File
file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_goTypes = nil
file_transport_internet_finalmask_mkcp_aes128gcm_config_proto_depIdxs = nil
}
@@ -0,0 +1,11 @@
syntax = "proto3";
package xray.transport.internet.finalmask.mkcp.aes128gcm;
option csharp_namespace = "Xray.Transport.Internet.Finalmask.Mkcp.Aes128Gcm";
option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/mkcp/aes128gcm";
option java_package = "com.xray.transport.internet.finalmask.mkcp.aes128gcm";
option java_multiple_files = true;
message Config {
string password = 1;
}
@@ -0,0 +1,174 @@
package aes128gcm
import (
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
"io"
"net"
sync "sync"
"time"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/crypto"
"github.com/xtls/xray-core/common/errors"
)
type aes128gcmConn struct {
first bool
leaveSize int32
conn net.PacketConn
aead cipher.AEAD
readBuf []byte
readMutex sync.Mutex
writeBuf []byte
writeMutex sync.Mutex
}
func NewConnClient(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
hashedPsk := sha256.Sum256([]byte(c.Password))
conn := &aes128gcmConn{
first: first,
leaveSize: leaveSize,
conn: raw,
aead: crypto.NewAesGcm(hashedPsk[:16]),
}
if first {
conn.readBuf = make([]byte, 8192)
conn.writeBuf = make([]byte, 8192)
}
return conn, nil
}
func NewConnServer(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
return NewConnClient(c, raw, first, leaveSize)
}
func (c *aes128gcmConn) Size() int32 {
return int32(c.aead.NonceSize()) + int32(c.aead.Overhead())
}
func (c *aes128gcmConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
if c.first {
c.readMutex.Lock()
n, addr, err = c.conn.ReadFrom(c.readBuf)
if err != nil {
c.readMutex.Unlock()
return n, addr, err
}
if n < int(c.Size()) {
c.readMutex.Unlock()
return 0, addr, errors.New("aead").Base(io.ErrShortBuffer)
}
if len(p) < n-int(c.Size()) {
c.readMutex.Unlock()
return 0, addr, errors.New("aead").Base(io.ErrShortBuffer)
}
nonceSize := c.aead.NonceSize()
nonce := c.readBuf[:nonceSize]
ciphertext := c.readBuf[nonceSize:n]
_, err = c.aead.Open(p[:0], nonce, ciphertext, nil)
if err != nil {
c.readMutex.Unlock()
return 0, addr, errors.New("aead open").Base(err)
}
c.readMutex.Unlock()
return n - int(c.Size()), addr, nil
}
n, addr, err = c.conn.ReadFrom(p)
if err != nil {
return n, addr, err
}
if n < int(c.Size()) {
return 0, addr, errors.New("aead").Base(io.ErrShortBuffer)
}
nonceSize := c.aead.NonceSize()
nonce := p[:nonceSize]
ciphertext := p[nonceSize:n]
_, err = c.aead.Open(ciphertext[:0], nonce, ciphertext, nil)
if err != nil {
return 0, addr, errors.New("aead open").Base(err)
}
copy(p, p[nonceSize:n-c.aead.Overhead()])
return n - int(c.Size()), addr, nil
}
func (c *aes128gcmConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
if c.first {
if c.leaveSize+c.Size()+int32(len(p)) > 8192 {
return 0, errors.New("too many masks")
}
c.writeMutex.Lock()
n = copy(c.writeBuf[c.leaveSize+int32(c.aead.NonceSize()):], p)
// n = copy(c.writeBuf[c.leaveSize+c.Size():], p)
n += int(c.leaveSize) + int(c.Size())
nonceSize := c.aead.NonceSize()
nonce := c.writeBuf[c.leaveSize : c.leaveSize+int32(nonceSize)]
common.Must2(rand.Read(nonce))
// copy(c.writeBuf[c.leaveSize+int32(nonceSize):], c.writeBuf[c.leaveSize+c.Size():n])
plaintext := c.writeBuf[c.leaveSize+int32(nonceSize) : n-c.aead.Overhead()]
_ = c.aead.Seal(plaintext[:0], nonce, plaintext, nil)
nn, err := c.conn.WriteTo(c.writeBuf[:n], addr)
if err != nil {
c.writeMutex.Unlock()
return 0, err
}
if nn != n {
c.writeMutex.Unlock()
return 0, errors.New("nn != n")
}
c.writeMutex.Unlock()
return len(p), nil
}
nonceSize := c.aead.NonceSize()
nonce := p[c.leaveSize : c.leaveSize+int32(nonceSize)]
common.Must2(rand.Read(nonce))
copy(p[c.leaveSize+int32(nonceSize):], p[c.leaveSize+c.Size():])
plaintext := p[c.leaveSize+int32(nonceSize) : len(p)-c.aead.Overhead()]
_ = c.aead.Seal(plaintext[:0], nonce, plaintext, nil)
return c.conn.WriteTo(p, addr)
}
func (c *aes128gcmConn) Close() error {
return c.conn.Close()
}
func (c *aes128gcmConn) LocalAddr() net.Addr {
return c.conn.LocalAddr()
}
func (c *aes128gcmConn) SetDeadline(t time.Time) error {
return c.conn.SetDeadline(t)
}
func (c *aes128gcmConn) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t)
}
func (c *aes128gcmConn) SetWriteDeadline(t time.Time) error {
return c.conn.SetWriteDeadline(t)
}
@@ -0,0 +1,16 @@
package original
import (
"net"
)
func (c *Config) UDP() {
}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnClient(c, raw, first, leaveSize)
}
func (c *Config) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnServer(c, raw, first, leaveSize)
}
@@ -0,0 +1,114 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v6.33.1
// source: transport/internet/finalmask/mkcp/original/config.proto
package original
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
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 `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Config) Reset() {
*x = Config{}
mi := &file_transport_internet_finalmask_mkcp_original_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_transport_internet_finalmask_mkcp_original_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_transport_internet_finalmask_mkcp_original_config_proto_rawDescGZIP(), []int{0}
}
var File_transport_internet_finalmask_mkcp_original_config_proto protoreflect.FileDescriptor
const file_transport_internet_finalmask_mkcp_original_config_proto_rawDesc = "" +
"\n" +
"7transport/internet/finalmask/mkcp/original/config.proto\x12/xray.transport.internet.finalmask.mkcp.original\"\b\n" +
"\x06ConfigB\xaf\x01\n" +
"3com.xray.transport.internet.finalmask.mkcp.originalP\x01ZDgithub.com/xtls/xray-core/transport/internet/finalmask/mkcp/original\xaa\x02/Xray.Transport.Internet.Finalmask.Mkcp.Originalb\x06proto3"
var (
file_transport_internet_finalmask_mkcp_original_config_proto_rawDescOnce sync.Once
file_transport_internet_finalmask_mkcp_original_config_proto_rawDescData []byte
)
func file_transport_internet_finalmask_mkcp_original_config_proto_rawDescGZIP() []byte {
file_transport_internet_finalmask_mkcp_original_config_proto_rawDescOnce.Do(func() {
file_transport_internet_finalmask_mkcp_original_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_mkcp_original_config_proto_rawDesc), len(file_transport_internet_finalmask_mkcp_original_config_proto_rawDesc)))
})
return file_transport_internet_finalmask_mkcp_original_config_proto_rawDescData
}
var file_transport_internet_finalmask_mkcp_original_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_transport_internet_finalmask_mkcp_original_config_proto_goTypes = []any{
(*Config)(nil), // 0: xray.transport.internet.finalmask.mkcp.original.Config
}
var file_transport_internet_finalmask_mkcp_original_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_transport_internet_finalmask_mkcp_original_config_proto_init() }
func file_transport_internet_finalmask_mkcp_original_config_proto_init() {
if File_transport_internet_finalmask_mkcp_original_config_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_mkcp_original_config_proto_rawDesc), len(file_transport_internet_finalmask_mkcp_original_config_proto_rawDesc)),
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_transport_internet_finalmask_mkcp_original_config_proto_goTypes,
DependencyIndexes: file_transport_internet_finalmask_mkcp_original_config_proto_depIdxs,
MessageInfos: file_transport_internet_finalmask_mkcp_original_config_proto_msgTypes,
}.Build()
File_transport_internet_finalmask_mkcp_original_config_proto = out.File
file_transport_internet_finalmask_mkcp_original_config_proto_goTypes = nil
file_transport_internet_finalmask_mkcp_original_config_proto_depIdxs = nil
}
@@ -0,0 +1,9 @@
syntax = "proto3";
package xray.transport.internet.finalmask.mkcp.original;
option csharp_namespace = "Xray.Transport.Internet.Finalmask.Mkcp.Original";
option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/mkcp/original";
option java_package = "com.xray.transport.internet.finalmask.mkcp.original";
option java_multiple_files = true;
message Config {}
@@ -0,0 +1,225 @@
package original
import (
"crypto/cipher"
"encoding/binary"
"hash/fnv"
"io"
"net"
sync "sync"
"time"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
)
type simple struct{}
func NewSimple() *simple {
return &simple{}
}
func (*simple) NonceSize() int {
return 0
}
func (*simple) Overhead() int {
return 6
}
func (a *simple) Seal(dst, nonce, plain, extra []byte) []byte {
dst = append(dst, 0, 0, 0, 0, 0, 0)
binary.BigEndian.PutUint16(dst[4:], uint16(len(plain)))
dst = append(dst, plain...)
fnvHash := fnv.New32a()
common.Must2(fnvHash.Write(dst[4:]))
fnvHash.Sum(dst[:0])
dstLen := len(dst)
xtra := 4 - dstLen%4
if xtra != 4 {
dst = append(dst, make([]byte, xtra)...)
}
xorfwd(dst)
if xtra != 4 {
dst = dst[:dstLen]
}
return dst
}
func (a *simple) Open(dst, nonce, cipherText, extra []byte) ([]byte, error) {
dst = append(dst, cipherText...)
dstLen := len(dst)
xtra := 4 - dstLen%4
if xtra != 4 {
dst = append(dst, make([]byte, xtra)...)
}
xorbkd(dst)
if xtra != 4 {
dst = dst[:dstLen]
}
fnvHash := fnv.New32a()
common.Must2(fnvHash.Write(dst[4:]))
if binary.BigEndian.Uint32(dst[:4]) != fnvHash.Sum32() {
return nil, errors.New("invalid auth")
}
length := binary.BigEndian.Uint16(dst[4:6])
if len(dst)-6 != int(length) {
return nil, errors.New("invalid auth")
}
return dst[6:], nil
}
type simpleConn struct {
first bool
leaveSize int32
conn net.PacketConn
aead cipher.AEAD
readBuf []byte
readMutex sync.Mutex
writeBuf []byte
writeMutex sync.Mutex
}
func NewConnClient(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
conn := &simpleConn{
first: first,
leaveSize: leaveSize,
conn: raw,
aead: &simple{},
}
if first {
conn.readBuf = make([]byte, 8192)
conn.writeBuf = make([]byte, 8192)
}
return conn, nil
}
func NewConnServer(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
return NewConnClient(c, raw, first, leaveSize)
}
func (c *simpleConn) Size() int32 {
return int32(c.aead.NonceSize()) + int32(c.aead.Overhead())
}
func (c *simpleConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
if c.first {
c.readMutex.Lock()
n, addr, err = c.conn.ReadFrom(c.readBuf)
if err != nil {
c.readMutex.Unlock()
return n, addr, err
}
if n < int(c.Size()) {
c.readMutex.Unlock()
return 0, addr, errors.New("aead").Base(io.ErrShortBuffer)
}
if len(p) < n-int(c.Size()) {
c.readMutex.Unlock()
return 0, addr, errors.New("aead").Base(io.ErrShortBuffer)
}
ciphertext := c.readBuf[:n]
opened, err := c.aead.Open(nil, nil, ciphertext, nil)
if err != nil {
c.readMutex.Unlock()
return 0, addr, errors.New("aead open").Base(err)
}
copy(p, opened)
c.readMutex.Unlock()
return n - int(c.Size()), addr, nil
}
n, addr, err = c.conn.ReadFrom(p)
if err != nil {
return n, addr, err
}
if n < int(c.Size()) {
return 0, addr, errors.New("aead").Base(io.ErrShortBuffer)
}
ciphertext := p[:n]
opened, err := c.aead.Open(nil, nil, ciphertext, nil)
if err != nil {
c.readMutex.Unlock()
return 0, addr, errors.New("aead open").Base(err)
}
copy(p, opened)
return n - int(c.Size()), addr, nil
}
func (c *simpleConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
if c.first {
if c.leaveSize+c.Size()+int32(len(p)) > 8192 {
return 0, errors.New("too many masks")
}
c.writeMutex.Lock()
n = copy(c.writeBuf[c.leaveSize+c.Size():], p)
n += int(c.leaveSize) + int(c.Size())
plaintext := c.writeBuf[c.leaveSize+c.Size() : n]
sealed := c.aead.Seal(nil, nil, plaintext, nil)
copy(c.writeBuf[c.leaveSize:], sealed)
nn, err := c.conn.WriteTo(c.writeBuf[:n], addr)
if err != nil {
c.writeMutex.Unlock()
return 0, err
}
if nn != n {
c.writeMutex.Unlock()
return 0, errors.New("nn != n")
}
c.writeMutex.Unlock()
return len(p), nil
}
plaintext := p[c.leaveSize+c.Size():]
sealed := c.aead.Seal(nil, nil, plaintext, nil)
copy(p[c.leaveSize:], sealed)
return c.conn.WriteTo(p, addr)
}
func (c *simpleConn) Close() error {
return c.conn.Close()
}
func (c *simpleConn) LocalAddr() net.Addr {
return c.conn.LocalAddr()
}
func (c *simpleConn) SetDeadline(t time.Time) error {
return c.conn.SetDeadline(t)
}
func (c *simpleConn) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t)
}
func (c *simpleConn) SetWriteDeadline(t time.Time) error {
return c.conn.SetWriteDeadline(t)
}
@@ -0,0 +1,19 @@
package original_test
import (
"crypto/rand"
"testing"
"github.com/stretchr/testify/assert"
"github.com/xtls/xray-core/transport/internet/finalmask/mkcp/original"
)
func TestOriginalBounce(t *testing.T) {
aead := original.NewSimple()
buf := make([]byte, aead.NonceSize()+aead.Overhead())
for i := 0; i < 1000; i++ {
_, _ = rand.Read(buf)
_, err := aead.Open(buf[:0], nil, buf, nil)
assert.NotEqual(t, err, nil)
}
}
@@ -1,7 +1,7 @@
//go:build !amd64 //go:build !amd64
// +build !amd64 // +build !amd64
package kcp package original
// xorfwd performs XOR forwards in words, x[i] ^= x[i-4], i from 0 to len // xorfwd performs XOR forwards in words, x[i] ^= x[i-4], i from 0 to len
func xorfwd(x []byte) { func xorfwd(x []byte) {
@@ -1,4 +1,4 @@
package kcp package original
//go:noescape //go:noescape
func xorfwd(x []byte) func xorfwd(x []byte)
@@ -2,41 +2,15 @@ package salamander
import ( import (
"net" "net"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/transport/internet/finalmask/salamander/obfs"
) )
func (c *Config) UDP() { func (c *Config) UDP() {
} }
func (c *Config) WrapConnClient(raw net.Conn) (net.Conn, error) { func (c *Config) WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return raw, nil return NewConnClient(c, raw, first, leaveSize)
} }
func (c *Config) WrapConnServer(raw net.Conn) (net.Conn, error) { func (c *Config) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return raw, nil return NewConnServer(c, raw, first, leaveSize)
}
func (c *Config) WrapPacketConnClient(raw net.PacketConn) (net.PacketConn, error) {
ob, err := obfs.NewSalamanderObfuscator([]byte(c.Password))
if err != nil {
return nil, errors.New("salamander err").Base(err)
}
return obfs.WrapPacketConn(raw, ob), nil
}
func (c *Config) WrapPacketConnServer(raw net.PacketConn) (net.PacketConn, error) {
ob, err := obfs.NewSalamanderObfuscator([]byte(c.Password))
if err != nil {
return nil, errors.New("salamander err").Base(err)
}
return obfs.WrapPacketConn(raw, ob), nil
}
func (c *Config) Size() int {
return 0
}
func (c *Config) Serialize([]byte) {
} }
@@ -2,7 +2,7 @@
// versions: // versions:
// protoc-gen-go v1.36.10 // protoc-gen-go v1.36.10
// protoc v6.33.1 // protoc v6.33.1
// source: transport/internet/udpmask/salamander/config.proto // source: transport/internet/finalmask/salamander/config.proto
package salamander package salamander
@@ -30,7 +30,7 @@ type Config struct {
func (x *Config) Reset() { func (x *Config) Reset() {
*x = Config{} *x = Config{}
mi := &file_transport_internet_udpmask_salamander_config_proto_msgTypes[0] mi := &file_transport_internet_finalmask_salamander_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -42,7 +42,7 @@ func (x *Config) String() string {
func (*Config) ProtoMessage() {} func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message { func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_udpmask_salamander_config_proto_msgTypes[0] mi := &file_transport_internet_finalmask_salamander_config_proto_msgTypes[0]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -55,7 +55,7 @@ func (x *Config) ProtoReflect() protoreflect.Message {
// Deprecated: Use Config.ProtoReflect.Descriptor instead. // Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) { func (*Config) Descriptor() ([]byte, []int) {
return file_transport_internet_udpmask_salamander_config_proto_rawDescGZIP(), []int{0} return file_transport_internet_finalmask_salamander_config_proto_rawDescGZIP(), []int{0}
} }
func (x *Config) GetPassword() string { func (x *Config) GetPassword() string {
@@ -65,32 +65,32 @@ func (x *Config) GetPassword() string {
return "" return ""
} }
var File_transport_internet_udpmask_salamander_config_proto protoreflect.FileDescriptor var File_transport_internet_finalmask_salamander_config_proto protoreflect.FileDescriptor
const file_transport_internet_udpmask_salamander_config_proto_rawDesc = "" + const file_transport_internet_finalmask_salamander_config_proto_rawDesc = "" +
"\n" + "\n" +
"2transport/internet/udpmask/salamander/config.proto\x12*xray.transport.internet.udpmask.salamander\"$\n" + "4transport/internet/finalmask/salamander/config.proto\x12,xray.transport.internet.finalmask.salamander\"$\n" +
"\x06Config\x12\x1a\n" + "\x06Config\x12\x1a\n" +
"\bpassword\x18\x01 \x01(\tR\bpasswordB\xa0\x01\n" + "\bpassword\x18\x01 \x01(\tR\bpasswordB\xa6\x01\n" +
".com.xray.transport.internet.udpmask.salamanderP\x01Z?github.com/xtls/xray-core/transport/internet/udpmask/salamander\xaa\x02*Xray.Transport.Internet.Udpmask.Salamanderb\x06proto3" "0com.xray.transport.internet.finalmask.salamanderP\x01ZAgithub.com/xtls/xray-core/transport/internet/finalmask/salamander\xaa\x02,Xray.Transport.Internet.Finalmask.Salamanderb\x06proto3"
var ( var (
file_transport_internet_udpmask_salamander_config_proto_rawDescOnce sync.Once file_transport_internet_finalmask_salamander_config_proto_rawDescOnce sync.Once
file_transport_internet_udpmask_salamander_config_proto_rawDescData []byte file_transport_internet_finalmask_salamander_config_proto_rawDescData []byte
) )
func file_transport_internet_udpmask_salamander_config_proto_rawDescGZIP() []byte { func file_transport_internet_finalmask_salamander_config_proto_rawDescGZIP() []byte {
file_transport_internet_udpmask_salamander_config_proto_rawDescOnce.Do(func() { file_transport_internet_finalmask_salamander_config_proto_rawDescOnce.Do(func() {
file_transport_internet_udpmask_salamander_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_udpmask_salamander_config_proto_rawDesc), len(file_transport_internet_udpmask_salamander_config_proto_rawDesc))) file_transport_internet_finalmask_salamander_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_salamander_config_proto_rawDesc), len(file_transport_internet_finalmask_salamander_config_proto_rawDesc)))
}) })
return file_transport_internet_udpmask_salamander_config_proto_rawDescData return file_transport_internet_finalmask_salamander_config_proto_rawDescData
} }
var file_transport_internet_udpmask_salamander_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_transport_internet_finalmask_salamander_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_transport_internet_udpmask_salamander_config_proto_goTypes = []any{ var file_transport_internet_finalmask_salamander_config_proto_goTypes = []any{
(*Config)(nil), // 0: xray.transport.internet.udpmask.salamander.Config (*Config)(nil), // 0: xray.transport.internet.finalmask.salamander.Config
} }
var file_transport_internet_udpmask_salamander_config_proto_depIdxs = []int32{ var file_transport_internet_finalmask_salamander_config_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type 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 method input_type
0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension type_name
@@ -98,26 +98,26 @@ var file_transport_internet_udpmask_salamander_config_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for field type_name 0, // [0:0] is the sub-list for field type_name
} }
func init() { file_transport_internet_udpmask_salamander_config_proto_init() } func init() { file_transport_internet_finalmask_salamander_config_proto_init() }
func file_transport_internet_udpmask_salamander_config_proto_init() { func file_transport_internet_finalmask_salamander_config_proto_init() {
if File_transport_internet_udpmask_salamander_config_proto != nil { if File_transport_internet_finalmask_salamander_config_proto != nil {
return return
} }
type x struct{} type x struct{}
out := protoimpl.TypeBuilder{ out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{ File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_udpmask_salamander_config_proto_rawDesc), len(file_transport_internet_udpmask_salamander_config_proto_rawDesc)), RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_salamander_config_proto_rawDesc), len(file_transport_internet_finalmask_salamander_config_proto_rawDesc)),
NumEnums: 0, NumEnums: 0,
NumMessages: 1, NumMessages: 1,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },
GoTypes: file_transport_internet_udpmask_salamander_config_proto_goTypes, GoTypes: file_transport_internet_finalmask_salamander_config_proto_goTypes,
DependencyIndexes: file_transport_internet_udpmask_salamander_config_proto_depIdxs, DependencyIndexes: file_transport_internet_finalmask_salamander_config_proto_depIdxs,
MessageInfos: file_transport_internet_udpmask_salamander_config_proto_msgTypes, MessageInfos: file_transport_internet_finalmask_salamander_config_proto_msgTypes,
}.Build() }.Build()
File_transport_internet_udpmask_salamander_config_proto = out.File File_transport_internet_finalmask_salamander_config_proto = out.File
file_transport_internet_udpmask_salamander_config_proto_goTypes = nil file_transport_internet_finalmask_salamander_config_proto_goTypes = nil
file_transport_internet_udpmask_salamander_config_proto_depIdxs = nil file_transport_internet_finalmask_salamander_config_proto_depIdxs = nil
} }
@@ -1,9 +1,9 @@
syntax = "proto3"; syntax = "proto3";
package xray.transport.internet.udpmask.salamander; package xray.transport.internet.finalmask.salamander;
option csharp_namespace = "Xray.Transport.Internet.Udpmask.Salamander"; option csharp_namespace = "Xray.Transport.Internet.Finalmask.Salamander";
option go_package = "github.com/xtls/xray-core/transport/internet/udpmask/salamander"; option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/salamander";
option java_package = "com.xray.transport.internet.udpmask.salamander"; option java_package = "com.xray.transport.internet.finalmask.salamander";
option java_multiple_files = true; option java_multiple_files = true;
message Config { message Config {
@@ -0,0 +1,147 @@
package salamander
import (
"io"
"net"
"sync"
"time"
"github.com/xtls/xray-core/common/errors"
)
type obfsPacketConn struct {
first bool
leaveSize int32
conn net.PacketConn
obfs *SalamanderObfuscator
readBuf []byte
readMutex sync.Mutex
writeBuf []byte
writeMutex sync.Mutex
}
func NewConnClient(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
ob, err := NewSalamanderObfuscator([]byte(c.Password))
if err != nil {
return nil, errors.New("salamander err").Base(err)
}
conn := &obfsPacketConn{
first: first,
leaveSize: leaveSize,
conn: raw,
obfs: ob,
}
if first {
conn.readBuf = make([]byte, 8192)
conn.writeBuf = make([]byte, 8192)
}
return conn, nil
}
func NewConnServer(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
return NewConnClient(c, raw, first, leaveSize)
}
func (c *obfsPacketConn) Size() int32 {
return smSaltLen
}
func (c *obfsPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
if c.first {
c.readMutex.Lock()
n, addr, err = c.conn.ReadFrom(c.readBuf)
if err != nil {
c.readMutex.Unlock()
return n, addr, err
}
if n < int(c.Size()) {
c.readMutex.Unlock()
return 0, addr, errors.New("salamander").Base(io.ErrShortBuffer)
}
if len(p) < n-int(c.Size()) {
c.readMutex.Unlock()
return 0, addr, errors.New("salamander").Base(io.ErrShortBuffer)
}
c.obfs.Deobfuscate(c.readBuf[:n], p)
c.readMutex.Unlock()
return n - int(c.Size()), addr, err
}
n, addr, err = c.conn.ReadFrom(p)
if err != nil {
return n, addr, err
}
if n < int(c.Size()) {
return 0, addr, errors.New("salamander").Base(io.ErrShortBuffer)
}
c.obfs.Deobfuscate(p[:n], p)
return n - int(c.Size()), addr, err
}
func (c *obfsPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
if c.first {
if c.leaveSize+c.Size()+int32(len(p)) > 8192 {
return 0, errors.New("too many masks")
}
c.writeMutex.Lock()
n = copy(c.writeBuf[c.leaveSize+c.Size():], p)
n += int(c.leaveSize) + int(c.Size())
c.obfs.Obfuscate(c.writeBuf[c.leaveSize+c.Size():n], c.writeBuf[c.leaveSize:n])
nn, err := c.conn.WriteTo(c.writeBuf[:n], addr)
if err != nil {
c.writeMutex.Unlock()
return 0, err
}
if nn != n {
c.writeMutex.Unlock()
return 0, errors.New("nn != n")
}
c.writeMutex.Unlock()
return len(p), nil
}
c.obfs.Obfuscate(p[c.leaveSize+c.Size():], p[c.leaveSize:])
return c.conn.WriteTo(p, addr)
}
func (c *obfsPacketConn) Close() error {
return c.conn.Close()
}
func (c *obfsPacketConn) LocalAddr() net.Addr {
return c.conn.LocalAddr()
}
func (c *obfsPacketConn) SetDeadline(t time.Time) error {
return c.conn.SetDeadline(t)
}
func (c *obfsPacketConn) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t)
}
func (c *obfsPacketConn) SetWriteDeadline(t time.Time) error {
return c.conn.SetWriteDeadline(t)
}
@@ -1,121 +0,0 @@
package obfs
import (
"net"
"sync"
"syscall"
"time"
)
const udpBufferSize = 2048 // QUIC packets are at most 1500 bytes long, so 2k should be more than enough
// Obfuscator is the interface that wraps the Obfuscate and Deobfuscate methods.
// Both methods return the number of bytes written to out.
// If a packet is not valid, the methods should return 0.
type Obfuscator interface {
Obfuscate(in, out []byte) int
Deobfuscate(in, out []byte) int
}
var _ net.PacketConn = (*obfsPacketConn)(nil)
type obfsPacketConn struct {
Conn net.PacketConn
Obfs Obfuscator
readBuf []byte
readMutex sync.Mutex
writeBuf []byte
writeMutex sync.Mutex
}
// obfsPacketConnUDP is a special case of obfsPacketConn that uses a UDPConn
// as the underlying connection. We pass additional methods to quic-go to
// enable UDP-specific optimizations.
type obfsPacketConnUDP struct {
*obfsPacketConn
UDPConn *net.UDPConn
}
// WrapPacketConn enables obfuscation on a net.PacketConn.
// The obfuscation is transparent to the caller - the n bytes returned by
// ReadFrom and WriteTo are the number of original bytes, not after
// obfuscation/deobfuscation.
func WrapPacketConn(conn net.PacketConn, obfs Obfuscator) net.PacketConn {
opc := &obfsPacketConn{
Conn: conn,
Obfs: obfs,
readBuf: make([]byte, udpBufferSize),
writeBuf: make([]byte, udpBufferSize),
}
if udpConn, ok := conn.(*net.UDPConn); ok {
return &obfsPacketConnUDP{
obfsPacketConn: opc,
UDPConn: udpConn,
}
} else {
return opc
}
}
func (c *obfsPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
for {
c.readMutex.Lock()
n, addr, err = c.Conn.ReadFrom(c.readBuf)
if n <= 0 {
c.readMutex.Unlock()
return n, addr, err
}
n = c.Obfs.Deobfuscate(c.readBuf[:n], p)
c.readMutex.Unlock()
if n > 0 || err != nil {
return n, addr, err
}
// Invalid packet, try again
}
}
func (c *obfsPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
c.writeMutex.Lock()
nn := c.Obfs.Obfuscate(p, c.writeBuf)
_, err = c.Conn.WriteTo(c.writeBuf[:nn], addr)
c.writeMutex.Unlock()
if err == nil {
n = len(p)
}
return n, err
}
func (c *obfsPacketConn) Close() error {
return c.Conn.Close()
}
func (c *obfsPacketConn) LocalAddr() net.Addr {
return c.Conn.LocalAddr()
}
func (c *obfsPacketConn) SetDeadline(t time.Time) error {
return c.Conn.SetDeadline(t)
}
func (c *obfsPacketConn) SetReadDeadline(t time.Time) error {
return c.Conn.SetReadDeadline(t)
}
func (c *obfsPacketConn) SetWriteDeadline(t time.Time) error {
return c.Conn.SetWriteDeadline(t)
}
// UDP-specific methods below
func (c *obfsPacketConnUDP) SetReadBuffer(bytes int) error {
return c.UDPConn.SetReadBuffer(bytes)
}
func (c *obfsPacketConnUDP) SetWriteBuffer(bytes int) error {
return c.UDPConn.SetWriteBuffer(bytes)
}
func (c *obfsPacketConnUDP) SyscallConn() (syscall.RawConn, error) {
return c.UDPConn.SyscallConn()
}
@@ -1,45 +0,0 @@
package obfs
import (
"crypto/rand"
"testing"
"github.com/stretchr/testify/assert"
)
func BenchmarkSalamanderObfuscator_Obfuscate(b *testing.B) {
o, _ := NewSalamanderObfuscator([]byte("average_password"))
in := make([]byte, 1200)
_, _ = rand.Read(in)
out := make([]byte, 2048)
b.ResetTimer()
for i := 0; i < b.N; i++ {
o.Obfuscate(in, out)
}
}
func BenchmarkSalamanderObfuscator_Deobfuscate(b *testing.B) {
o, _ := NewSalamanderObfuscator([]byte("average_password"))
in := make([]byte, 1200)
_, _ = rand.Read(in)
out := make([]byte, 2048)
b.ResetTimer()
for i := 0; i < b.N; i++ {
o.Deobfuscate(in, out)
}
}
func TestSalamanderObfuscator(t *testing.T) {
o, _ := NewSalamanderObfuscator([]byte("average_password"))
in := make([]byte, 1200)
oOut := make([]byte, 2048)
dOut := make([]byte, 2048)
for i := 0; i < 1000; i++ {
_, _ = rand.Read(in)
n := o.Obfuscate(in, oOut)
assert.Equal(t, len(in)+smSaltLen, n)
n = o.Deobfuscate(oOut[:n], dOut)
assert.Equal(t, len(in), n)
assert.Equal(t, in, dOut[:n])
}
}
@@ -1,4 +1,4 @@
package obfs package salamander
import ( import (
"fmt" "fmt"
@@ -15,8 +15,6 @@ const (
smKeyLen = blake2b.Size256 smKeyLen = blake2b.Size256
) )
var _ Obfuscator = (*SalamanderObfuscator)(nil)
var ErrPSKTooShort = fmt.Errorf("PSK must be at least %d bytes", smPSKMinLen) var ErrPSKTooShort = fmt.Errorf("PSK must be at least %d bytes", smPSKMinLen)
// SalamanderObfuscator is an obfuscator that obfuscates each packet with // SalamanderObfuscator is an obfuscator that obfuscates each packet with
@@ -0,0 +1,81 @@
package salamander_test
import (
"crypto/rand"
"testing"
"github.com/stretchr/testify/assert"
"github.com/xtls/xray-core/transport/internet/finalmask/salamander"
)
const (
smSaltLen = 8
)
func BenchmarkSalamanderObfuscator_Obfuscate(b *testing.B) {
o, _ := salamander.NewSalamanderObfuscator([]byte("average_password"))
in := make([]byte, 1200)
_, _ = rand.Read(in)
out := make([]byte, 2048)
b.ResetTimer()
for i := 0; i < b.N; i++ {
o.Obfuscate(in, out)
}
}
func BenchmarkSalamanderObfuscator_Deobfuscate(b *testing.B) {
o, _ := salamander.NewSalamanderObfuscator([]byte("average_password"))
in := make([]byte, 1200)
_, _ = rand.Read(in)
out := make([]byte, 2048)
b.ResetTimer()
for i := 0; i < b.N; i++ {
o.Deobfuscate(in, out)
}
}
func TestSalamanderObfuscator(t *testing.T) {
o, _ := salamander.NewSalamanderObfuscator([]byte("average_password"))
in := make([]byte, 1200)
oOut := make([]byte, 2048)
dOut := make([]byte, 2048)
for i := 0; i < 1000; i++ {
_, _ = rand.Read(in)
n := o.Obfuscate(in, oOut)
assert.Equal(t, len(in)+smSaltLen, n)
n = o.Deobfuscate(oOut[:n], dOut)
assert.Equal(t, len(in), n)
assert.Equal(t, in, dOut[:n])
}
}
func TestSalamanderInPlace(t *testing.T) {
o, _ := salamander.NewSalamanderObfuscator([]byte("average_password"))
in := make([]byte, 1200)
out := make([]byte, 2048)
_, _ = rand.Read(in)
o.Obfuscate(in, out)
out2 := make([]byte, 2048)
copy(out2[smSaltLen:], in)
o.Obfuscate(out2[smSaltLen:], out2)
dOut := make([]byte, 2048)
o.Deobfuscate(out, dOut)
o.Deobfuscate(out2, out2)
assert.Equal(t, in, dOut[:1200])
assert.Equal(t, in, out2[:1200])
}
func TestSalamanderBounce(t *testing.T) {
o, _ := salamander.NewSalamanderObfuscator([]byte("average_password"))
buf := make([]byte, 8)
for i := 0; i < 1000; i++ {
_, _ = rand.Read(buf)
n := o.Deobfuscate(buf, buf)
assert.Equal(t, 0, n)
}
}
+129
View File
@@ -0,0 +1,129 @@
package finalmask_test
import (
"bytes"
"net"
"testing"
"time"
"github.com/xtls/xray-core/transport/internet/finalmask"
"github.com/xtls/xray-core/transport/internet/finalmask/header/dns"
"github.com/xtls/xray-core/transport/internet/finalmask/header/srtp"
"github.com/xtls/xray-core/transport/internet/finalmask/header/utp"
"github.com/xtls/xray-core/transport/internet/finalmask/header/wechat"
"github.com/xtls/xray-core/transport/internet/finalmask/header/wireguard"
"github.com/xtls/xray-core/transport/internet/finalmask/mkcp/aes128gcm"
"github.com/xtls/xray-core/transport/internet/finalmask/mkcp/original"
"github.com/xtls/xray-core/transport/internet/finalmask/salamander"
)
func mustSendRecv(
t *testing.T,
from net.PacketConn,
to net.PacketConn,
msg []byte,
) {
t.Helper()
go func() {
_, err := from.WriteTo(msg, to.LocalAddr())
if err != nil {
t.Error(err)
}
}()
buf := make([]byte, 1024)
n, _, err := to.ReadFrom(buf)
if err != nil {
t.Fatal(err)
}
if n != len(msg) {
t.Fatalf("unexpected size: %d", n)
}
if !bytes.Equal(buf[:n], msg) {
t.Fatalf("unexpected data")
}
}
type layerMask struct {
name string
mask finalmask.Udpmask
}
func TestPacketConnReadWrite(t *testing.T) {
cases := []layerMask{
{
name: "aes128gcm",
mask: &aes128gcm.Config{Password: "123"},
},
{
name: "original",
mask: &original.Config{},
},
{
name: "dns",
mask: &dns.Config{Domain: "www.baidu.com"},
},
{
name: "srtp",
mask: &srtp.Config{},
},
{
name: "utp",
mask: &utp.Config{},
},
{
name: "wechat",
mask: &wechat.Config{},
},
{
name: "wireguard",
mask: &wireguard.Config{},
},
{
name: "salamander",
mask: &salamander.Config{Password: "1234"},
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
mask := c.mask
maskManager := finalmask.NewUdpmaskManager([]finalmask.Udpmask{mask, mask})
client, err := net.ListenPacket("udp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
defer client.Close()
client, err = maskManager.WrapPacketConnClient(client)
if err != nil {
t.Fatal(err)
}
server, err := net.ListenPacket("udp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
defer server.Close()
server, err = maskManager.WrapPacketConnServer(server)
if err != nil {
t.Fatal(err)
}
_ = client.SetDeadline(time.Now().Add(time.Second))
_ = server.SetDeadline(time.Now().Add(time.Second))
mustSendRecv(t, client, server, []byte("client -> server"))
mustSendRecv(t, server, client, []byte("server -> client"))
mustSendRecv(t, client, server, []byte{})
mustSendRecv(t, server, client, []byte{})
})
}
}
+373
View File
@@ -0,0 +1,373 @@
package xdns
import (
"bytes"
"context"
"crypto/rand"
"encoding/base32"
"encoding/binary"
"io"
"net"
"sync"
"time"
"github.com/xtls/xray-core/common/errors"
)
const (
numPadding = 3
numPaddingForPoll = 8
initPollDelay = 500 * time.Millisecond
maxPollDelay = 10 * time.Second
pollDelayMultiplier = 2.0
pollLimit = 16
)
var base32Encoding = base32.StdEncoding.WithPadding(base32.NoPadding)
type packet struct {
p []byte
addr net.Addr
}
type xdnsConnClient struct {
conn net.PacketConn
clientID []byte
domain Name
pollChan chan struct{}
readQueue chan *packet
writeQueue chan *packet
closed bool
mutex sync.Mutex
}
func NewConnClient(c *Config, raw net.PacketConn, end bool) (net.PacketConn, error) {
if !end {
return nil, errors.New("xdns requires being at the outermost level")
}
domain, err := ParseName(c.Domain)
if err != nil {
return nil, err
}
conn := &xdnsConnClient{
conn: raw,
clientID: make([]byte, 8),
domain: domain,
pollChan: make(chan struct{}, pollLimit),
readQueue: make(chan *packet, 128),
writeQueue: make(chan *packet, 128),
}
rand.Read(conn.clientID)
go conn.recvLoop()
go conn.sendLoop()
return conn, nil
}
func (c *xdnsConnClient) recvLoop() {
for {
if c.closed {
break
}
var buf [4096]byte
n, addr, err := c.conn.ReadFrom(buf[:])
if err != nil {
continue
}
resp, err := MessageFromWireFormat(buf[:n])
if err != nil {
continue
}
payload := dnsResponsePayload(&resp, c.domain)
r := bytes.NewReader(payload)
anyPacket := false
for {
p, err := nextPacket(r)
if err != nil {
break
}
anyPacket = true
buf := make([]byte, len(p))
copy(buf, p)
select {
case c.readQueue <- &packet{
p: buf,
addr: addr,
}:
default:
}
}
if anyPacket {
select {
case c.pollChan <- struct{}{}:
default:
}
}
}
close(c.pollChan)
close(c.readQueue)
}
func (c *xdnsConnClient) sendLoop() {
var addr net.Addr
pollDelay := initPollDelay
pollTimer := time.NewTimer(pollDelay)
for {
var p *packet
pollTimerExpired := false
select {
case p = <-c.writeQueue:
default:
select {
case p = <-c.writeQueue:
case <-c.pollChan:
case <-pollTimer.C:
pollTimerExpired = true
}
}
if p != nil {
addr = p.addr
select {
case <-c.pollChan:
default:
}
} else if addr != nil {
encoded, _ := encode(nil, c.clientID, c.domain)
p = &packet{
p: encoded,
addr: addr,
}
}
if pollTimerExpired {
pollDelay = time.Duration(float64(pollDelay) * pollDelayMultiplier)
if pollDelay > maxPollDelay {
pollDelay = maxPollDelay
}
} else {
if !pollTimer.Stop() {
<-pollTimer.C
}
pollDelay = initPollDelay
}
pollTimer.Reset(pollDelay)
if c.closed {
return
}
if p != nil {
_, _ = c.conn.WriteTo(p.p, p.addr)
}
}
}
func (c *xdnsConnClient) Size() int32 {
return 0
}
func (c *xdnsConnClient) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
packet, ok := <-c.readQueue
if !ok {
return 0, nil, io.EOF
}
n = copy(p, packet.p)
if n != len(packet.p) {
return 0, nil, io.ErrShortBuffer
}
return n, packet.addr, nil
}
func (c *xdnsConnClient) WriteTo(p []byte, addr net.Addr) (n int, err error) {
c.mutex.Lock()
defer c.mutex.Unlock()
if c.closed {
return 0, errors.New("xdns closed")
}
encoded, err := encode(p, c.clientID, c.domain)
if err != nil {
errors.LogDebug(context.Background(), "xdns encode err", err)
return 0, errors.New("xdns encode").Base(err)
}
select {
case c.writeQueue <- &packet{
p: encoded,
addr: addr,
}:
return len(p), nil
default:
return 0, errors.New("xdns queue full")
}
}
func (c *xdnsConnClient) Close() error {
c.mutex.Lock()
defer c.mutex.Unlock()
if c.closed {
return nil
}
c.closed = true
close(c.writeQueue)
return c.conn.Close()
}
func (c *xdnsConnClient) LocalAddr() net.Addr {
return c.conn.LocalAddr()
}
func (c *xdnsConnClient) SetDeadline(t time.Time) error {
return c.conn.SetDeadline(t)
}
func (c *xdnsConnClient) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t)
}
func (c *xdnsConnClient) SetWriteDeadline(t time.Time) error {
return c.conn.SetWriteDeadline(t)
}
func encode(p []byte, clientID []byte, domain Name) ([]byte, error) {
var decoded []byte
{
if len(p) >= 224 {
return nil, errors.New("too long")
}
var buf bytes.Buffer
buf.Write(clientID[:])
n := numPadding
if len(p) == 0 {
n = numPaddingForPoll
}
buf.WriteByte(byte(224 + n))
_, _ = io.CopyN(&buf, rand.Reader, int64(n))
if len(p) > 0 {
buf.WriteByte(byte(len(p)))
buf.Write(p)
}
decoded = buf.Bytes()
}
encoded := make([]byte, base32Encoding.EncodedLen(len(decoded)))
base32Encoding.Encode(encoded, decoded)
encoded = bytes.ToLower(encoded)
labels := chunks(encoded, 63)
labels = append(labels, domain...)
name, err := NewName(labels)
if err != nil {
return nil, err
}
var id uint16
_ = binary.Read(rand.Reader, binary.BigEndian, &id)
query := &Message{
ID: id,
Flags: 0x0100,
Question: []Question{
{
Name: name,
Type: RRTypeTXT,
Class: ClassIN,
},
},
Additional: []RR{
{
Name: Name{},
Type: RRTypeOPT,
Class: 4096,
TTL: 0,
Data: []byte{},
},
},
}
buf, err := query.WireFormat()
if err != nil {
return nil, err
}
return buf, nil
}
func chunks(p []byte, n int) [][]byte {
var result [][]byte
for len(p) > 0 {
sz := len(p)
if sz > n {
sz = n
}
result = append(result, p[:sz])
p = p[sz:]
}
return result
}
func nextPacket(r *bytes.Reader) ([]byte, error) {
var n uint16
err := binary.Read(r, binary.BigEndian, &n)
if err != nil {
return nil, err
}
p := make([]byte, n)
_, err = io.ReadFull(r, p)
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return p, err
}
func dnsResponsePayload(resp *Message, domain Name) []byte {
if resp.Flags&0x8000 != 0x8000 {
return nil
}
if resp.Flags&0x000f != RcodeNoError {
return nil
}
if len(resp.Answer) != 1 {
return nil
}
answer := resp.Answer[0]
_, ok := answer.Name.TrimSuffix(domain)
if !ok {
return nil
}
if answer.Type != RRTypeTXT {
return nil
}
payload, err := DecodeRDataTXT(answer.Data)
if err != nil {
return nil
}
return payload
}
@@ -0,0 +1,16 @@
package xdns
import (
"net"
)
func (c *Config) UDP() {
}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnClient(c, raw, end)
}
func (c *Config) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnServer(c, raw, end)
}
@@ -0,0 +1,123 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v6.33.1
// source: transport/internet/finalmask/xdns/config.proto
package xdns
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
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 `protogen:"open.v1"`
Domain string `protobuf:"bytes,1,opt,name=domain,proto3" json:"domain,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Config) Reset() {
*x = Config{}
mi := &file_transport_internet_finalmask_xdns_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_transport_internet_finalmask_xdns_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_transport_internet_finalmask_xdns_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetDomain() string {
if x != nil {
return x.Domain
}
return ""
}
var File_transport_internet_finalmask_xdns_config_proto protoreflect.FileDescriptor
const file_transport_internet_finalmask_xdns_config_proto_rawDesc = "" +
"\n" +
".transport/internet/finalmask/xdns/config.proto\x12&xray.transport.internet.finalmask.xdns\" \n" +
"\x06Config\x12\x16\n" +
"\x06domain\x18\x01 \x01(\tR\x06domainB\x94\x01\n" +
"*com.xray.transport.internet.finalmask.xdnsP\x01Z;github.com/xtls/xray-core/transport/internet/finalmask/xdns\xaa\x02&Xray.Transport.Internet.Finalmask.Xdnsb\x06proto3"
var (
file_transport_internet_finalmask_xdns_config_proto_rawDescOnce sync.Once
file_transport_internet_finalmask_xdns_config_proto_rawDescData []byte
)
func file_transport_internet_finalmask_xdns_config_proto_rawDescGZIP() []byte {
file_transport_internet_finalmask_xdns_config_proto_rawDescOnce.Do(func() {
file_transport_internet_finalmask_xdns_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_xdns_config_proto_rawDesc), len(file_transport_internet_finalmask_xdns_config_proto_rawDesc)))
})
return file_transport_internet_finalmask_xdns_config_proto_rawDescData
}
var file_transport_internet_finalmask_xdns_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_transport_internet_finalmask_xdns_config_proto_goTypes = []any{
(*Config)(nil), // 0: xray.transport.internet.finalmask.xdns.Config
}
var file_transport_internet_finalmask_xdns_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_transport_internet_finalmask_xdns_config_proto_init() }
func file_transport_internet_finalmask_xdns_config_proto_init() {
if File_transport_internet_finalmask_xdns_config_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_xdns_config_proto_rawDesc), len(file_transport_internet_finalmask_xdns_config_proto_rawDesc)),
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_transport_internet_finalmask_xdns_config_proto_goTypes,
DependencyIndexes: file_transport_internet_finalmask_xdns_config_proto_depIdxs,
MessageInfos: file_transport_internet_finalmask_xdns_config_proto_msgTypes,
}.Build()
File_transport_internet_finalmask_xdns_config_proto = out.File
file_transport_internet_finalmask_xdns_config_proto_goTypes = nil
file_transport_internet_finalmask_xdns_config_proto_depIdxs = nil
}
@@ -0,0 +1,12 @@
syntax = "proto3";
package xray.transport.internet.finalmask.xdns;
option csharp_namespace = "Xray.Transport.Internet.Finalmask.Xdns";
option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/xdns";
option java_package = "com.xray.transport.internet.finalmask.xdns";
option java_multiple_files = true;
message Config {
string domain = 1;
}
+575
View File
@@ -0,0 +1,575 @@
// Package dns deals with encoding and decoding DNS wire format.
package xdns
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"strings"
)
// The maximum number of DNS name compression pointers we are willing to follow.
// Without something like this, infinite loops are possible.
const compressionPointerLimit = 10
var (
// ErrZeroLengthLabel is the error returned for names that contain a
// zero-length label, like "example..com".
ErrZeroLengthLabel = errors.New("name contains a zero-length label")
// ErrLabelTooLong is the error returned for labels that are longer than
// 63 octets.
ErrLabelTooLong = errors.New("name contains a label longer than 63 octets")
// ErrNameTooLong is the error returned for names whose encoded
// representation is longer than 255 octets.
ErrNameTooLong = errors.New("name is longer than 255 octets")
// ErrReservedLabelType is the error returned when reading a label type
// prefix whose two most significant bits are not 00 or 11.
ErrReservedLabelType = errors.New("reserved label type")
// ErrTooManyPointers is the error returned when reading a compressed
// name that has too many compression pointers.
ErrTooManyPointers = errors.New("too many compression pointers")
// ErrTrailingBytes is the error returned when bytes remain in the parse
// buffer after parsing a message.
ErrTrailingBytes = errors.New("trailing bytes after message")
// ErrIntegerOverflow is the error returned when trying to encode an
// integer greater than 65535 into a 16-bit field.
ErrIntegerOverflow = errors.New("integer overflow")
)
const (
// https://tools.ietf.org/html/rfc1035#section-3.2.2
RRTypeTXT = 16
// https://tools.ietf.org/html/rfc6891#section-6.1.1
RRTypeOPT = 41
// https://tools.ietf.org/html/rfc1035#section-3.2.4
ClassIN = 1
// https://tools.ietf.org/html/rfc1035#section-4.1.1
RcodeNoError = 0 // a.k.a. NOERROR
RcodeFormatError = 1 // a.k.a. FORMERR
RcodeNameError = 3 // a.k.a. NXDOMAIN
RcodeNotImplemented = 4 // a.k.a. NOTIMPL
// https://tools.ietf.org/html/rfc6891#section-9
ExtendedRcodeBadVers = 16 // a.k.a. BADVERS
)
// Name represents a domain name, a sequence of labels each of which is 63
// octets or less in length.
//
// https://tools.ietf.org/html/rfc1035#section-3.1
type Name [][]byte
// NewName returns a Name from a slice of labels, after checking the labels for
// validity. Does not include a zero-length label at the end of the slice.
func NewName(labels [][]byte) (Name, error) {
name := Name(labels)
// https://tools.ietf.org/html/rfc1035#section-2.3.4
// Various objects and parameters in the DNS have size limits.
// labels 63 octets or less
// names 255 octets or less
for _, label := range labels {
if len(label) == 0 {
return nil, ErrZeroLengthLabel
}
if len(label) > 63 {
return nil, ErrLabelTooLong
}
}
// Check the total length.
builder := newMessageBuilder()
builder.WriteName(name)
if len(builder.Bytes()) > 255 {
return nil, ErrNameTooLong
}
return name, nil
}
// ParseName returns a new Name from a string of labels separated by dots, after
// checking the name for validity. A single dot at the end of the string is
// ignored.
func ParseName(s string) (Name, error) {
b := bytes.TrimSuffix([]byte(s), []byte("."))
if len(b) == 0 {
// bytes.Split(b, ".") would return [""] in this case
return NewName([][]byte{})
} else {
return NewName(bytes.Split(b, []byte(".")))
}
}
// String returns a reversible string representation of name. Labels are
// separated by dots, and any bytes in a label that are outside the set
// [0-9A-Za-z-] are replaced with a \xXX hex escape sequence.
func (name Name) String() string {
if len(name) == 0 {
return "."
}
var buf strings.Builder
for i, label := range name {
if i > 0 {
buf.WriteByte('.')
}
for _, b := range label {
if b == '-' ||
('0' <= b && b <= '9') ||
('A' <= b && b <= 'Z') ||
('a' <= b && b <= 'z') {
buf.WriteByte(b)
} else {
fmt.Fprintf(&buf, "\\x%02x", b)
}
}
}
return buf.String()
}
// TrimSuffix returns a Name with the given suffix removed, if it was present.
// The second return value indicates whether the suffix was present. If the
// suffix was not present, the first return value is nil.
func (name Name) TrimSuffix(suffix Name) (Name, bool) {
if len(name) < len(suffix) {
return nil, false
}
split := len(name) - len(suffix)
fore, aft := name[:split], name[split:]
for i := 0; i < len(aft); i++ {
if !bytes.Equal(bytes.ToLower(aft[i]), bytes.ToLower(suffix[i])) {
return nil, false
}
}
return fore, true
}
// Message represents a DNS message.
//
// https://tools.ietf.org/html/rfc1035#section-4.1
type Message struct {
ID uint16
Flags uint16
Question []Question
Answer []RR
Authority []RR
Additional []RR
}
// Opcode extracts the OPCODE part of the Flags field.
//
// https://tools.ietf.org/html/rfc1035#section-4.1.1
func (message *Message) Opcode() uint16 {
return (message.Flags >> 11) & 0xf
}
// Rcode extracts the RCODE part of the Flags field.
//
// https://tools.ietf.org/html/rfc1035#section-4.1.1
func (message *Message) Rcode() uint16 {
return message.Flags & 0x000f
}
// Question represents an entry in the question section of a message.
//
// https://tools.ietf.org/html/rfc1035#section-4.1.2
type Question struct {
Name Name
Type uint16
Class uint16
}
// RR represents a resource record.
//
// https://tools.ietf.org/html/rfc1035#section-4.1.3
type RR struct {
Name Name
Type uint16
Class uint16
TTL uint32
Data []byte
}
// readName parses a DNS name from r. It leaves r positioned just after the
// parsed name.
func readName(r io.ReadSeeker) (Name, error) {
var labels [][]byte
// We limit the number of compression pointers we are willing to follow.
numPointers := 0
// If we followed any compression pointers, we must finally seek to just
// past the first pointer.
var seekTo int64
loop:
for {
var labelType byte
err := binary.Read(r, binary.BigEndian, &labelType)
if err != nil {
return nil, err
}
switch labelType & 0xc0 {
case 0x00:
// This is an ordinary label.
// https://tools.ietf.org/html/rfc1035#section-3.1
length := int(labelType & 0x3f)
if length == 0 {
break loop
}
label := make([]byte, length)
_, err := io.ReadFull(r, label)
if err != nil {
return nil, err
}
labels = append(labels, label)
case 0xc0:
// This is a compression pointer.
// https://tools.ietf.org/html/rfc1035#section-4.1.4
upper := labelType & 0x3f
var lower byte
err := binary.Read(r, binary.BigEndian, &lower)
if err != nil {
return nil, err
}
offset := (uint16(upper) << 8) | uint16(lower)
if numPointers == 0 {
// The first time we encounter a pointer,
// remember our position so we can seek back to
// it when done.
seekTo, err = r.Seek(0, io.SeekCurrent)
if err != nil {
return nil, err
}
}
numPointers++
if numPointers > compressionPointerLimit {
return nil, ErrTooManyPointers
}
// Follow the pointer and continue.
_, err = r.Seek(int64(offset), io.SeekStart)
if err != nil {
return nil, err
}
default:
// "The 10 and 01 combinations are reserved for future
// use."
return nil, ErrReservedLabelType
}
}
// If we followed any pointers, then seek back to just after the first
// one.
if numPointers > 0 {
_, err := r.Seek(seekTo, io.SeekStart)
if err != nil {
return nil, err
}
}
return NewName(labels)
}
// readQuestion parses one entry from the Question section. It leaves r
// positioned just after the parsed entry.
//
// https://tools.ietf.org/html/rfc1035#section-4.1.2
func readQuestion(r io.ReadSeeker) (Question, error) {
var question Question
var err error
question.Name, err = readName(r)
if err != nil {
return question, err
}
for _, ptr := range []*uint16{&question.Type, &question.Class} {
err := binary.Read(r, binary.BigEndian, ptr)
if err != nil {
return question, err
}
}
return question, nil
}
// readRR parses one resource record. It leaves r positioned just after the
// parsed resource record.
//
// https://tools.ietf.org/html/rfc1035#section-4.1.3
func readRR(r io.ReadSeeker) (RR, error) {
var rr RR
var err error
rr.Name, err = readName(r)
if err != nil {
return rr, err
}
for _, ptr := range []*uint16{&rr.Type, &rr.Class} {
err := binary.Read(r, binary.BigEndian, ptr)
if err != nil {
return rr, err
}
}
err = binary.Read(r, binary.BigEndian, &rr.TTL)
if err != nil {
return rr, err
}
var rdLength uint16
err = binary.Read(r, binary.BigEndian, &rdLength)
if err != nil {
return rr, err
}
rr.Data = make([]byte, rdLength)
_, err = io.ReadFull(r, rr.Data)
if err != nil {
return rr, err
}
return rr, nil
}
// readMessage parses a complete DNS message. It leaves r positioned just after
// the parsed message.
func readMessage(r io.ReadSeeker) (Message, error) {
var message Message
// Header section
// https://tools.ietf.org/html/rfc1035#section-4.1.1
var qdCount, anCount, nsCount, arCount uint16
for _, ptr := range []*uint16{
&message.ID, &message.Flags,
&qdCount, &anCount, &nsCount, &arCount,
} {
err := binary.Read(r, binary.BigEndian, ptr)
if err != nil {
return message, err
}
}
// Question section
// https://tools.ietf.org/html/rfc1035#section-4.1.2
for i := 0; i < int(qdCount); i++ {
question, err := readQuestion(r)
if err != nil {
return message, err
}
message.Question = append(message.Question, question)
}
// Answer, Authority, and Additional sections
// https://tools.ietf.org/html/rfc1035#section-4.1.3
for _, rec := range []struct {
ptr *[]RR
count uint16
}{
{&message.Answer, anCount},
{&message.Authority, nsCount},
{&message.Additional, arCount},
} {
for i := 0; i < int(rec.count); i++ {
rr, err := readRR(r)
if err != nil {
return message, err
}
*rec.ptr = append(*rec.ptr, rr)
}
}
return message, nil
}
// MessageFromWireFormat parses a message from buf and returns a Message object.
// It returns ErrTrailingBytes if there are bytes remaining in buf after parsing
// is done.
func MessageFromWireFormat(buf []byte) (Message, error) {
r := bytes.NewReader(buf)
message, err := readMessage(r)
if err == io.EOF {
err = io.ErrUnexpectedEOF
} else if err == nil {
// Check for trailing bytes.
_, err = r.ReadByte()
if err == io.EOF {
err = nil
} else if err == nil {
err = ErrTrailingBytes
}
}
return message, err
}
// messageBuilder manages the state of serializing a DNS message. Its main
// function is to keep track of names already written for the purpose of name
// compression.
type messageBuilder struct {
w bytes.Buffer
nameCache map[string]int
}
// newMessageBuilder creates a new messageBuilder with an empty name cache.
func newMessageBuilder() *messageBuilder {
return &messageBuilder{
nameCache: make(map[string]int),
}
}
// Bytes returns the serialized DNS message as a slice of bytes.
func (builder *messageBuilder) Bytes() []byte {
return builder.w.Bytes()
}
// WriteName appends name to the in-progress messageBuilder, employing
// compression pointers to previously written names if possible.
func (builder *messageBuilder) WriteName(name Name) {
// https://tools.ietf.org/html/rfc1035#section-3.1
for i := range name {
// Has this suffix already been encoded in the message?
if ptr, ok := builder.nameCache[name[i:].String()]; ok && ptr&0x3fff == ptr {
// If so, we can write a compression pointer.
binary.Write(&builder.w, binary.BigEndian, uint16(0xc000|ptr))
return
}
// Not cached; we must encode this label verbatim. Store a cache
// entry pointing to the beginning of it.
builder.nameCache[name[i:].String()] = builder.w.Len()
length := len(name[i])
if length == 0 || length > 63 {
panic(length)
}
builder.w.WriteByte(byte(length))
builder.w.Write(name[i])
}
builder.w.WriteByte(0)
}
// WriteQuestion appends a Question section entry to the in-progress
// messageBuilder.
func (builder *messageBuilder) WriteQuestion(question *Question) {
// https://tools.ietf.org/html/rfc1035#section-4.1.2
builder.WriteName(question.Name)
binary.Write(&builder.w, binary.BigEndian, question.Type)
binary.Write(&builder.w, binary.BigEndian, question.Class)
}
// WriteRR appends a resource record to the in-progress messageBuilder. It
// returns ErrIntegerOverflow if the length of rr.Data does not fit in 16 bits.
func (builder *messageBuilder) WriteRR(rr *RR) error {
// https://tools.ietf.org/html/rfc1035#section-4.1.3
builder.WriteName(rr.Name)
binary.Write(&builder.w, binary.BigEndian, rr.Type)
binary.Write(&builder.w, binary.BigEndian, rr.Class)
binary.Write(&builder.w, binary.BigEndian, rr.TTL)
rdLength := uint16(len(rr.Data))
if int(rdLength) != len(rr.Data) {
return ErrIntegerOverflow
}
binary.Write(&builder.w, binary.BigEndian, rdLength)
builder.w.Write(rr.Data)
return nil
}
// WriteMessage appends a complete DNS message to the in-progress
// messageBuilder. It returns ErrIntegerOverflow if the number of entries in any
// section, or the length of the data in any resource record, does not fit in 16
// bits.
func (builder *messageBuilder) WriteMessage(message *Message) error {
// Header section
// https://tools.ietf.org/html/rfc1035#section-4.1.1
binary.Write(&builder.w, binary.BigEndian, message.ID)
binary.Write(&builder.w, binary.BigEndian, message.Flags)
for _, count := range []int{
len(message.Question),
len(message.Answer),
len(message.Authority),
len(message.Additional),
} {
count16 := uint16(count)
if int(count16) != count {
return ErrIntegerOverflow
}
binary.Write(&builder.w, binary.BigEndian, count16)
}
// Question section
// https://tools.ietf.org/html/rfc1035#section-4.1.2
for _, question := range message.Question {
builder.WriteQuestion(&question)
}
// Answer, Authority, and Additional sections
// https://tools.ietf.org/html/rfc1035#section-4.1.3
for _, rrs := range [][]RR{message.Answer, message.Authority, message.Additional} {
for _, rr := range rrs {
err := builder.WriteRR(&rr)
if err != nil {
return err
}
}
}
return nil
}
// WireFormat encodes a Message as a slice of bytes in DNS wire format. It
// returns ErrIntegerOverflow if the number of entries in any section, or the
// length of the data in any resource record, does not fit in 16 bits.
func (message *Message) WireFormat() ([]byte, error) {
builder := newMessageBuilder()
err := builder.WriteMessage(message)
if err != nil {
return nil, err
}
return builder.Bytes(), nil
}
// DecodeRDataTXT decodes TXT-DATA (as found in the RDATA for a resource record
// with TYPE=TXT) as a raw byte slice, by concatenating all the
// <character-string>s it contains.
//
// https://tools.ietf.org/html/rfc1035#section-3.3.14
func DecodeRDataTXT(p []byte) ([]byte, error) {
var buf bytes.Buffer
for {
if len(p) == 0 {
return nil, io.ErrUnexpectedEOF
}
n := int(p[0])
p = p[1:]
if len(p) < n {
return nil, io.ErrUnexpectedEOF
}
buf.Write(p[:n])
p = p[n:]
if len(p) == 0 {
break
}
}
return buf.Bytes(), nil
}
// EncodeRDataTXT encodes a slice of bytes as TXT-DATA, as appropriate for the
// RDATA of a resource record with TYPE=TXT. No length restriction is enforced
// here; that must be checked at a higher level.
//
// https://tools.ietf.org/html/rfc1035#section-3.3.14
func EncodeRDataTXT(p []byte) []byte {
// https://tools.ietf.org/html/rfc1035#section-3.3
// https://tools.ietf.org/html/rfc1035#section-3.3.14
// TXT data is a sequence of one or more <character-string>s, where
// <character-string> is a length octet followed by that number of
// octets.
var buf bytes.Buffer
for len(p) > 255 {
buf.WriteByte(255)
buf.Write(p[:255])
p = p[255:]
}
// Must write here, even if len(p) == 0, because it's "*one or more*
// <character-string>s".
buf.WriteByte(byte(len(p)))
buf.Write(p)
return buf.Bytes()
}
@@ -0,0 +1,592 @@
package xdns
import (
"bytes"
"fmt"
"io"
"strconv"
"strings"
"testing"
)
func namesEqual(a, b Name) bool {
if len(a) != len(b) {
return false
}
for i := 0; i < len(a); i++ {
if !bytes.Equal(a[i], b[i]) {
return false
}
}
return true
}
func TestName(t *testing.T) {
for _, test := range []struct {
labels [][]byte
err error
s string
}{
{[][]byte{}, nil, "."},
{[][]byte{[]byte("test")}, nil, "test"},
{[][]byte{[]byte("a"), []byte("b"), []byte("c")}, nil, "a.b.c"},
{[][]byte{{}}, ErrZeroLengthLabel, ""},
{[][]byte{[]byte("a"), {}, []byte("c")}, ErrZeroLengthLabel, ""},
// 63 octets.
{[][]byte{[]byte("0123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABCDE")}, nil,
"0123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABCDE"},
// 64 octets.
{[][]byte{[]byte("0123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABCDEF")}, ErrLabelTooLong, ""},
// 64+64+64+62 octets.
{[][]byte{
[]byte("0123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABCDE"),
[]byte("0123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABCDE"),
[]byte("0123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABCDE"),
[]byte("0123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABC"),
}, nil,
"0123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABCDE.0123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABCDE.0123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABCDE.0123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABC"},
// 64+64+64+63 octets.
{[][]byte{
[]byte("0123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABCDE"),
[]byte("0123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABCDE"),
[]byte("0123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABCDE"),
[]byte("0123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABCD"),
}, ErrNameTooLong, ""},
// 127 one-octet labels.
{[][]byte{
{'0'}, {'1'}, {'2'}, {'3'}, {'4'}, {'5'}, {'6'}, {'7'}, {'8'}, {'9'}, {'a'}, {'b'}, {'c'}, {'d'}, {'e'}, {'f'},
{'0'}, {'1'}, {'2'}, {'3'}, {'4'}, {'5'}, {'6'}, {'7'}, {'8'}, {'9'}, {'A'}, {'B'}, {'C'}, {'D'}, {'E'}, {'F'},
{'0'}, {'1'}, {'2'}, {'3'}, {'4'}, {'5'}, {'6'}, {'7'}, {'8'}, {'9'}, {'a'}, {'b'}, {'c'}, {'d'}, {'e'}, {'f'},
{'0'}, {'1'}, {'2'}, {'3'}, {'4'}, {'5'}, {'6'}, {'7'}, {'8'}, {'9'}, {'A'}, {'B'}, {'C'}, {'D'}, {'E'}, {'F'},
{'0'}, {'1'}, {'2'}, {'3'}, {'4'}, {'5'}, {'6'}, {'7'}, {'8'}, {'9'}, {'a'}, {'b'}, {'c'}, {'d'}, {'e'}, {'f'},
{'0'}, {'1'}, {'2'}, {'3'}, {'4'}, {'5'}, {'6'}, {'7'}, {'8'}, {'9'}, {'A'}, {'B'}, {'C'}, {'D'}, {'E'}, {'F'},
{'0'}, {'1'}, {'2'}, {'3'}, {'4'}, {'5'}, {'6'}, {'7'}, {'8'}, {'9'}, {'a'}, {'b'}, {'c'}, {'d'}, {'e'}, {'f'},
{'0'}, {'1'}, {'2'}, {'3'}, {'4'}, {'5'}, {'6'}, {'7'}, {'8'}, {'9'}, {'A'}, {'B'}, {'C'}, {'D'}, {'E'},
}, nil,
"0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F.0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E"},
// 128 one-octet labels.
{[][]byte{
{'0'}, {'1'}, {'2'}, {'3'}, {'4'}, {'5'}, {'6'}, {'7'}, {'8'}, {'9'}, {'a'}, {'b'}, {'c'}, {'d'}, {'e'}, {'f'},
{'0'}, {'1'}, {'2'}, {'3'}, {'4'}, {'5'}, {'6'}, {'7'}, {'8'}, {'9'}, {'A'}, {'B'}, {'C'}, {'D'}, {'E'}, {'F'},
{'0'}, {'1'}, {'2'}, {'3'}, {'4'}, {'5'}, {'6'}, {'7'}, {'8'}, {'9'}, {'a'}, {'b'}, {'c'}, {'d'}, {'e'}, {'f'},
{'0'}, {'1'}, {'2'}, {'3'}, {'4'}, {'5'}, {'6'}, {'7'}, {'8'}, {'9'}, {'A'}, {'B'}, {'C'}, {'D'}, {'E'}, {'F'},
{'0'}, {'1'}, {'2'}, {'3'}, {'4'}, {'5'}, {'6'}, {'7'}, {'8'}, {'9'}, {'a'}, {'b'}, {'c'}, {'d'}, {'e'}, {'f'},
{'0'}, {'1'}, {'2'}, {'3'}, {'4'}, {'5'}, {'6'}, {'7'}, {'8'}, {'9'}, {'A'}, {'B'}, {'C'}, {'D'}, {'E'}, {'F'},
{'0'}, {'1'}, {'2'}, {'3'}, {'4'}, {'5'}, {'6'}, {'7'}, {'8'}, {'9'}, {'a'}, {'b'}, {'c'}, {'d'}, {'e'}, {'f'},
{'0'}, {'1'}, {'2'}, {'3'}, {'4'}, {'5'}, {'6'}, {'7'}, {'8'}, {'9'}, {'A'}, {'B'}, {'C'}, {'D'}, {'E'}, {'F'},
}, ErrNameTooLong, ""},
} {
// Test that NewName returns proper error codes, and otherwise
// returns an equal slice of labels.
name, err := NewName(test.labels)
if err != test.err || (err == nil && !namesEqual(name, test.labels)) {
t.Errorf("%+q returned (%+q, %v), expected (%+q, %v)",
test.labels, name, err, test.labels, test.err)
continue
}
if test.err != nil {
continue
}
// Test that the string version of the name comes out as
// expected.
s := name.String()
if s != test.s {
t.Errorf("%+q became string %+q, expected %+q", test.labels, s, test.s)
continue
}
// Test that parsing from a string back to a Name results in the
// original slice of labels.
name, err = ParseName(s)
if err != nil || !namesEqual(name, test.labels) {
t.Errorf("%+q parsing %+q returned (%+q, %v), expected (%+q, %v)",
test.labels, s, name, err, test.labels, nil)
continue
}
// A trailing dot should be ignored.
if !strings.HasSuffix(s, ".") {
dotName, dotErr := ParseName(s + ".")
if dotErr != err || !namesEqual(dotName, name) {
t.Errorf("%+q parsing %+q returned (%+q, %v), expected (%+q, %v)",
test.labels, s+".", dotName, dotErr, name, err)
continue
}
}
}
}
func TestParseName(t *testing.T) {
for _, test := range []struct {
s string
name Name
err error
}{
// This case can't be tested by TestName above because String
// will never produce "" (it produces "." instead).
{"", [][]byte{}, nil},
} {
name, err := ParseName(test.s)
if err != test.err || (err == nil && !namesEqual(name, test.name)) {
t.Errorf("%+q returned (%+q, %v), expected (%+q, %v)",
test.s, name, err, test.name, test.err)
continue
}
}
}
func unescapeString(s string) ([][]byte, error) {
if s == "." {
return [][]byte{}, nil
}
var result [][]byte
for _, label := range strings.Split(s, ".") {
var buf bytes.Buffer
i := 0
for i < len(label) {
switch label[i] {
case '\\':
if i+3 >= len(label) {
return nil, fmt.Errorf("truncated escape sequence at index %v", i)
}
if label[i+1] != 'x' {
return nil, fmt.Errorf("malformed escape sequence at index %v", i)
}
b, err := strconv.ParseUint(string(label[i+2:i+4]), 16, 8)
if err != nil {
return nil, fmt.Errorf("malformed hex sequence at index %v", i+2)
}
buf.WriteByte(byte(b))
i += 4
default:
buf.WriteByte(label[i])
i++
}
}
result = append(result, buf.Bytes())
}
return result, nil
}
func TestNameString(t *testing.T) {
for _, test := range []struct {
name Name
s string
}{
{[][]byte{}, "."},
{[][]byte{[]byte("\x00"), []byte("a.b"), []byte("c\nd\\")}, "\\x00.a\\x2eb.c\\x0ad\\x5c"},
{[][]byte{
[]byte("\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>"),
[]byte("?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}"),
[]byte("~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc"),
[]byte("\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb"),
[]byte("\xfc\xfd\xfe\xff"),
}, "\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f\\x20\\x21\\x22\\x23\\x24\\x25\\x26\\x27\\x28\\x29\\x2a\\x2b\\x2c-\\x2e\\x2f0123456789\\x3a\\x3b\\x3c\\x3d\\x3e.\\x3f\\x40ABCDEFGHIJKLMNOPQRSTUVWXYZ\\x5b\\x5c\\x5d\\x5e\\x5f\\x60abcdefghijklmnopqrstuvwxyz\\x7b\\x7c\\x7d.\\x7e\\x7f\\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87\\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f\\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\\x98\\x99\\x9a\\x9b\\x9c\\x9d\\x9e\\x9f\\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\\xb0\\xb1\\xb2\\xb3\\xb4\\xb5\\xb6\\xb7\\xb8\\xb9\\xba\\xbb\\xbc.\\xbd\\xbe\\xbf\\xc0\\xc1\\xc2\\xc3\\xc4\\xc5\\xc6\\xc7\\xc8\\xc9\\xca\\xcb\\xcc\\xcd\\xce\\xcf\\xd0\\xd1\\xd2\\xd3\\xd4\\xd5\\xd6\\xd7\\xd8\\xd9\\xda\\xdb\\xdc\\xdd\\xde\\xdf\\xe0\\xe1\\xe2\\xe3\\xe4\\xe5\\xe6\\xe7\\xe8\\xe9\\xea\\xeb\\xec\\xed\\xee\\xef\\xf0\\xf1\\xf2\\xf3\\xf4\\xf5\\xf6\\xf7\\xf8\\xf9\\xfa\\xfb.\\xfc\\xfd\\xfe\\xff"},
} {
s := test.name.String()
if s != test.s {
t.Errorf("%+q escaped to %+q, expected %+q", test.name, s, test.s)
continue
}
unescaped, err := unescapeString(s)
if err != nil {
t.Errorf("%+q unescaping %+q resulted in error %v", test.name, s, err)
continue
}
if !namesEqual(Name(unescaped), test.name) {
t.Errorf("%+q roundtripped through %+q to %+q", test.name, s, unescaped)
continue
}
}
}
func TestNameTrimSuffix(t *testing.T) {
for _, test := range []struct {
name, suffix string
trimmed string
ok bool
}{
{"", "", ".", true},
{".", ".", ".", true},
{"abc", "", "abc", true},
{"abc", ".", "abc", true},
{"", "abc", ".", false},
{".", "abc", ".", false},
{"example.com", "com", "example", true},
{"example.com", "net", ".", false},
{"example.com", "example.com", ".", true},
{"example.com", "test.com", ".", false},
{"example.com", "xample.com", ".", false},
{"example.com", "example", ".", false},
{"example.com", "COM", "example", true},
{"EXAMPLE.COM", "com", "EXAMPLE", true},
} {
tmp, ok := mustParseName(test.name).TrimSuffix(mustParseName(test.suffix))
trimmed := tmp.String()
if ok != test.ok || trimmed != test.trimmed {
t.Errorf("TrimSuffix %+q %+q returned (%+q, %v), expected (%+q, %v)",
test.name, test.suffix, trimmed, ok, test.trimmed, test.ok)
continue
}
}
}
func TestReadName(t *testing.T) {
// Good tests.
for _, test := range []struct {
start int64
end int64
input string
s string
}{
// Empty name.
{0, 1, "\x00abcd", "."},
// No pointers.
{12, 25, "AAAABBBBCCCC\x07example\x03com\x00", "example.com"},
// Backward pointer.
{25, 31, "AAAABBBBCCCC\x07example\x03com\x00\x03sub\xc0\x0c", "sub.example.com"},
// Forward pointer.
{0, 4, "\x01a\xc0\x04\x03bcd\x00", "a.bcd"},
// Two backwards pointers.
{31, 38, "AAAABBBBCCCC\x07example\x03com\x00\x03sub\xc0\x0c\x04sub2\xc0\x19", "sub2.sub.example.com"},
// Forward then backward pointer.
{25, 31, "AAAABBBBCCCC\x07example\x03com\x00\x03sub\xc0\x1f\x04sub2\xc0\x0c", "sub.sub2.example.com"},
// Overlapping codons.
{0, 4, "\x01a\xc0\x03bcd\x00", "a.bcd"},
// Pointer to empty label.
{0, 10, "\x07example\xc0\x0a\x00", "example"},
{1, 11, "\x00\x07example\xc0\x00", "example"},
// Pointer to pointer to empty label.
{0, 10, "\x07example\xc0\x0a\xc0\x0c\x00", "example"},
{1, 11, "\x00\x07example\xc0\x0c\xc0\x00", "example"},
} {
r := bytes.NewReader([]byte(test.input))
_, err := r.Seek(test.start, io.SeekStart)
if err != nil {
panic(err)
}
name, err := readName(r)
if err != nil {
t.Errorf("%+q returned error %s", test.input, err)
continue
}
s := name.String()
if s != test.s {
t.Errorf("%+q returned %+q, expected %+q", test.input, s, test.s)
continue
}
cur, _ := r.Seek(0, io.SeekCurrent)
if cur != test.end {
t.Errorf("%+q left offset %d, expected %d", test.input, cur, test.end)
continue
}
}
// Bad tests.
for _, test := range []struct {
start int64
input string
err error
}{
{0, "", io.ErrUnexpectedEOF},
// Reserved label type.
{0, "\x80example", ErrReservedLabelType},
// Reserved label type.
{0, "\x40example", ErrReservedLabelType},
// No Terminating empty label.
{0, "\x07example\x03com", io.ErrUnexpectedEOF},
// Pointer past end of buffer.
{0, "\x07example\xc0\xff", io.ErrUnexpectedEOF},
// Pointer to self.
{0, "\x07example\x03com\xc0\x0c", ErrTooManyPointers},
// Pointer to self with intermediate label.
{0, "\x07example\x03com\xc0\x08", ErrTooManyPointers},
// Two pointers that point to each other.
{0, "\xc0\x02\xc0\x00", ErrTooManyPointers},
// Two pointers that point to each other, with intermediate labels.
{0, "\x01a\xc0\x04\x01b\xc0\x00", ErrTooManyPointers},
// EOF while reading label.
{0, "\x0aexample", io.ErrUnexpectedEOF},
// EOF before second byte of pointer.
{0, "\xc0", io.ErrUnexpectedEOF},
{0, "\x07example\xc0", io.ErrUnexpectedEOF},
} {
r := bytes.NewReader([]byte(test.input))
_, err := r.Seek(test.start, io.SeekStart)
if err != nil {
panic(err)
}
name, err := readName(r)
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
if err != test.err {
t.Errorf("%+q returned (%+q, %v), expected %v", test.input, name, err, test.err)
continue
}
}
}
func mustParseName(s string) Name {
name, err := ParseName(s)
if err != nil {
panic(err)
}
return name
}
func questionsEqual(a, b *Question) bool {
if !namesEqual(a.Name, b.Name) {
return false
}
if a.Type != b.Type || a.Class != b.Class {
return false
}
return true
}
func rrsEqual(a, b *RR) bool {
if !namesEqual(a.Name, b.Name) {
return false
}
if a.Type != b.Type || a.Class != b.Class || a.TTL != b.TTL {
return false
}
if !bytes.Equal(a.Data, b.Data) {
return false
}
return true
}
func messagesEqual(a, b *Message) bool {
if a.ID != b.ID || a.Flags != b.Flags {
return false
}
if len(a.Question) != len(b.Question) {
return false
}
for i := 0; i < len(a.Question); i++ {
if !questionsEqual(&a.Question[i], &b.Question[i]) {
return false
}
}
for _, rec := range []struct{ rrA, rrB []RR }{
{a.Answer, b.Answer},
{a.Authority, b.Authority},
{a.Additional, b.Additional},
} {
if len(rec.rrA) != len(rec.rrB) {
return false
}
for i := 0; i < len(rec.rrA); i++ {
if !rrsEqual(&rec.rrA[i], &rec.rrB[i]) {
return false
}
}
}
return true
}
func TestMessageFromWireFormat(t *testing.T) {
for _, test := range []struct {
buf string
expected Message
err error
}{
{
"\x12\x34",
Message{},
io.ErrUnexpectedEOF,
},
{
"\x12\x34\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03www\x07example\x03com\x00\x00\x01\x00\x01",
Message{
ID: 0x1234,
Flags: 0x0100,
Question: []Question{
{
Name: mustParseName("www.example.com"),
Type: 1,
Class: 1,
},
},
Answer: []RR{},
Authority: []RR{},
Additional: []RR{},
},
nil,
},
{
"\x12\x34\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03www\x07example\x03com\x00\x00\x01\x00\x01X",
Message{},
ErrTrailingBytes,
},
{
"\x12\x34\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\x03www\x07example\x03com\x00\x00\x01\x00\x01\x03www\x07example\x03com\x00\x00\x01\x00\x01\x00\x00\x00\x80\x00\x04\xc0\x00\x02\x01",
Message{
ID: 0x1234,
Flags: 0x8180,
Question: []Question{
{
Name: mustParseName("www.example.com"),
Type: 1,
Class: 1,
},
},
Answer: []RR{
{
Name: mustParseName("www.example.com"),
Type: 1,
Class: 1,
TTL: 128,
Data: []byte{192, 0, 2, 1},
},
},
Authority: []RR{},
Additional: []RR{},
},
nil,
},
} {
message, err := MessageFromWireFormat([]byte(test.buf))
if err != test.err || (err == nil && !messagesEqual(&message, &test.expected)) {
t.Errorf("%+q\nreturned (%+v, %v)\nexpected (%+v, %v)",
test.buf, message, err, test.expected, test.err)
continue
}
}
}
func TestMessageWireFormatRoundTrip(t *testing.T) {
for _, message := range []Message{
{
ID: 0x1234,
Flags: 0x0100,
Question: []Question{
{
Name: mustParseName("www.example.com"),
Type: 1,
Class: 1,
},
{
Name: mustParseName("www2.example.com"),
Type: 2,
Class: 2,
},
},
Answer: []RR{
{
Name: mustParseName("abc"),
Type: 2,
Class: 3,
TTL: 0xffffffff,
Data: []byte{1},
},
{
Name: mustParseName("xyz"),
Type: 2,
Class: 3,
TTL: 255,
Data: []byte{},
},
},
Authority: []RR{
{
Name: mustParseName("."),
Type: 65535,
Class: 65535,
TTL: 0,
Data: []byte("XXXXXXXXXXXXXXXXXXX"),
},
},
Additional: []RR{},
},
} {
buf, err := message.WireFormat()
if err != nil {
t.Errorf("%+v cannot make wire format: %v", message, err)
continue
}
message2, err := MessageFromWireFormat(buf)
if err != nil {
t.Errorf("%+q cannot parse wire format: %v", buf, err)
continue
}
if !messagesEqual(&message, &message2) {
t.Errorf("messages unequal\nbefore: %+v\n after: %+v", message, message2)
continue
}
}
}
func TestDecodeRDataTXT(t *testing.T) {
for _, test := range []struct {
p []byte
decoded []byte
err error
}{
{[]byte{}, nil, io.ErrUnexpectedEOF},
{[]byte("\x00"), []byte{}, nil},
{[]byte("\x01"), nil, io.ErrUnexpectedEOF},
} {
decoded, err := DecodeRDataTXT(test.p)
if err != test.err || (err == nil && !bytes.Equal(decoded, test.decoded)) {
t.Errorf("%+q\nreturned (%+q, %v)\nexpected (%+q, %v)",
test.p, decoded, err, test.decoded, test.err)
continue
}
}
}
func TestEncodeRDataTXT(t *testing.T) {
// Encoding 0 bytes needs to return at least a single length octet of
// zero, not an empty slice.
p := make([]byte, 0)
encoded := EncodeRDataTXT(p)
if len(encoded) < 0 {
t.Errorf("EncodeRDataTXT(%v) returned %v", p, encoded)
}
// 255 bytes should be able to be encoded into 256 bytes.
p = make([]byte, 255)
encoded = EncodeRDataTXT(p)
if len(encoded) > 256 {
t.Errorf("EncodeRDataTXT(%d bytes) returned %d bytes", len(p), len(encoded))
}
}
func TestRDataTXTRoundTrip(t *testing.T) {
for _, p := range [][]byte{
{},
[]byte("\x00"),
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
},
} {
rdata := EncodeRDataTXT(p)
decoded, err := DecodeRDataTXT(rdata)
if err != nil || !bytes.Equal(decoded, p) {
t.Errorf("%+q returned (%+q, %v)", p, decoded, err)
continue
}
}
}
+567
View File
@@ -0,0 +1,567 @@
package xdns
import (
"bytes"
"context"
"encoding/binary"
"io"
"net"
"sync"
"time"
"github.com/xtls/xray-core/common/errors"
)
const (
idleTimeout = 2 * time.Minute
responseTTL = 60
maxResponseDelay = 1 * time.Second
)
var (
maxUDPPayload = 1280 - 40 - 8
maxEncodedPayload = computeMaxEncodedPayload(maxUDPPayload)
)
func clientIDToAddr(clientID [8]byte) *net.UDPAddr {
ip := make(net.IP, 16)
copy(ip, []byte{0xfd, 0x00, 0, 0, 0, 0, 0, 0})
copy(ip[8:], clientID[:])
return &net.UDPAddr{
IP: ip,
}
}
type record struct {
Resp *Message
Addr net.Addr
// ClientID [8]byte
ClientAddr net.Addr
}
type queue struct {
lash time.Time
queue chan []byte
stash chan []byte
}
type xdnsConnServer struct {
conn net.PacketConn
domain Name
ch chan *record
readQueue chan *packet
writeQueueMap map[string]*queue
closed bool
mutex sync.Mutex
}
func NewConnServer(c *Config, raw net.PacketConn, end bool) (net.PacketConn, error) {
if !end {
return nil, errors.New("xdns requires being at the outermost level")
}
domain, err := ParseName(c.Domain)
if err != nil {
return nil, err
}
conn := &xdnsConnServer{
conn: raw,
domain: domain,
ch: make(chan *record, 100),
readQueue: make(chan *packet, 128),
writeQueueMap: make(map[string]*queue),
}
go conn.clean()
go conn.recvLoop()
go conn.sendLoop()
return conn, nil
}
func (c *xdnsConnServer) clean() {
f := func() bool {
c.mutex.Lock()
defer c.mutex.Unlock()
if c.closed {
return true
}
now := time.Now()
for key, q := range c.writeQueueMap {
if now.Sub(q.lash) >= idleTimeout {
close(q.queue)
close(q.stash)
delete(c.writeQueueMap, key)
}
}
return false
}
for {
time.Sleep(idleTimeout / 2)
if f() {
return
}
}
}
func (c *xdnsConnServer) ensureQueue(addr net.Addr) *queue {
c.mutex.Lock()
defer c.mutex.Unlock()
if c.closed {
return nil
}
q, ok := c.writeQueueMap[addr.String()]
if !ok {
q = &queue{
queue: make(chan []byte, 128),
stash: make(chan []byte, 1),
}
c.writeQueueMap[addr.String()] = q
}
q.lash = time.Now()
return q
}
func (c *xdnsConnServer) stash(queue *queue, p []byte) {
c.mutex.Lock()
defer c.mutex.Unlock()
if c.closed {
return
}
select {
case queue.stash <- p:
default:
}
}
func (c *xdnsConnServer) recvLoop() {
for {
if c.closed {
break
}
var buf [4096]byte
n, addr, err := c.conn.ReadFrom(buf[:])
if err != nil {
continue
}
query, err := MessageFromWireFormat(buf[:n])
if err != nil {
continue
}
resp, payload := responseFor(&query, c.domain)
var clientID [8]byte
n = copy(clientID[:], payload)
payload = payload[n:]
if n == len(clientID) {
r := bytes.NewReader(payload)
for {
p, err := nextPacketServer(r)
if err != nil {
break
}
buf := make([]byte, len(p))
copy(buf, p)
select {
case c.readQueue <- &packet{
p: buf,
addr: clientIDToAddr(clientID),
}:
default:
}
}
} else {
if resp != nil && resp.Rcode() == RcodeNoError {
resp.Flags |= RcodeNameError
}
}
if resp != nil {
select {
case c.ch <- &record{resp, addr, clientIDToAddr(clientID)}:
default:
}
}
}
close(c.ch)
close(c.readQueue)
}
func (c *xdnsConnServer) sendLoop() {
var nextRec *record
for {
rec := nextRec
nextRec = nil
if rec == nil {
var ok bool
rec, ok = <-c.ch
if !ok {
break
}
}
if rec.Resp.Rcode() == RcodeNoError && len(rec.Resp.Question) == 1 {
rec.Resp.Answer = []RR{
{
Name: rec.Resp.Question[0].Name,
Type: rec.Resp.Question[0].Type,
Class: rec.Resp.Question[0].Class,
TTL: responseTTL,
Data: nil,
},
}
var payload bytes.Buffer
limit := maxEncodedPayload
timer := time.NewTimer(maxResponseDelay)
for {
queue := c.ensureQueue(rec.ClientAddr)
if queue == nil {
return
}
var p []byte
select {
case p = <-queue.stash:
default:
select {
case p = <-queue.stash:
case p = <-queue.queue:
default:
select {
case p = <-queue.stash:
case p = <-queue.queue:
case <-timer.C:
case nextRec = <-c.ch:
}
}
}
timer.Reset(0)
if len(p) == 0 {
break
}
limit -= 2 + len(p)
if payload.Len() == 0 {
} else if limit < 0 {
c.stash(queue, p)
break
}
if int(uint16(len(p))) != len(p) {
panic(len(p))
}
_ = binary.Write(&payload, binary.BigEndian, uint16(len(p)))
payload.Write(p)
}
timer.Stop()
rec.Resp.Answer[0].Data = EncodeRDataTXT(payload.Bytes())
}
buf, err := rec.Resp.WireFormat()
if err != nil {
continue
}
if len(buf) > maxUDPPayload {
errors.LogDebug(context.Background(), "xdns server truncate ", len(buf))
buf = buf[:maxUDPPayload]
buf[2] |= 0x02
}
if c.closed {
return
}
_, _ = c.conn.WriteTo(buf, rec.Addr)
}
}
func (c *xdnsConnServer) Size() int32 {
return 0
}
func (c *xdnsConnServer) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
packet, ok := <-c.readQueue
if !ok {
return 0, nil, io.EOF
}
n = copy(p, packet.p)
if n != len(packet.p) {
return 0, nil, io.ErrShortBuffer
}
return n, packet.addr, nil
}
func (c *xdnsConnServer) WriteTo(p []byte, addr net.Addr) (n int, err error) {
q := c.ensureQueue(addr)
if q == nil {
return 0, errors.New("xdns closed")
}
c.mutex.Lock()
defer c.mutex.Unlock()
if c.closed {
return 0, errors.New("xdns closed")
}
buf := make([]byte, len(p))
copy(buf, p)
select {
case q.queue <- buf:
return len(p), nil
default:
return 0, errors.New("xdns queue full")
}
}
func (c *xdnsConnServer) Close() error {
c.mutex.Lock()
defer c.mutex.Unlock()
if c.closed {
return nil
}
c.closed = true
for key, q := range c.writeQueueMap {
close(q.queue)
close(q.stash)
delete(c.writeQueueMap, key)
}
return c.conn.Close()
}
func (c *xdnsConnServer) LocalAddr() net.Addr {
return c.conn.LocalAddr()
}
func (c *xdnsConnServer) SetDeadline(t time.Time) error {
return c.conn.SetDeadline(t)
}
func (c *xdnsConnServer) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t)
}
func (c *xdnsConnServer) SetWriteDeadline(t time.Time) error {
return c.conn.SetWriteDeadline(t)
}
func nextPacketServer(r *bytes.Reader) ([]byte, error) {
eof := func(err error) error {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return err
}
for {
prefix, err := r.ReadByte()
if err != nil {
return nil, err
}
if prefix >= 224 {
paddingLen := prefix - 224
_, err := io.CopyN(io.Discard, r, int64(paddingLen))
if err != nil {
return nil, eof(err)
}
} else {
p := make([]byte, int(prefix))
_, err = io.ReadFull(r, p)
return p, eof(err)
}
}
}
func responseFor(query *Message, domain Name) (*Message, []byte) {
resp := &Message{
ID: query.ID,
Flags: 0x8000,
Question: query.Question,
}
if query.Flags&0x8000 != 0 {
return nil, nil
}
payloadSize := 0
for _, rr := range query.Additional {
if rr.Type != RRTypeOPT {
continue
}
if len(resp.Additional) != 0 {
resp.Flags |= RcodeFormatError
return resp, nil
}
resp.Additional = append(resp.Additional, RR{
Name: Name{},
Type: RRTypeOPT,
Class: 4096,
TTL: 0,
Data: []byte{},
})
additional := &resp.Additional[0]
version := (rr.TTL >> 16) & 0xff
if version != 0 {
resp.Flags |= ExtendedRcodeBadVers & 0xf
additional.TTL = (ExtendedRcodeBadVers >> 4) << 24
return resp, nil
}
payloadSize = int(rr.Class)
}
if payloadSize < 512 {
payloadSize = 512
}
if len(query.Question) != 1 {
resp.Flags |= RcodeFormatError
return resp, nil
}
question := query.Question[0]
prefix, ok := question.Name.TrimSuffix(domain)
if !ok {
resp.Flags |= RcodeNameError
return resp, nil
}
resp.Flags |= 0x0400
if query.Opcode() != 0 {
resp.Flags |= RcodeNotImplemented
return resp, nil
}
if question.Type != RRTypeTXT {
resp.Flags |= RcodeNameError
return resp, nil
}
encoded := bytes.ToUpper(bytes.Join(prefix, nil))
payload := make([]byte, base32Encoding.DecodedLen(len(encoded)))
n, err := base32Encoding.Decode(payload, encoded)
if err != nil {
resp.Flags |= RcodeNameError
return resp, nil
}
payload = payload[:n]
if payloadSize < maxUDPPayload {
resp.Flags |= RcodeFormatError
return resp, nil
}
return resp, payload
}
func computeMaxEncodedPayload(limit int) int {
maxLengthName, err := NewName([][]byte{
[]byte("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"),
[]byte("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"),
[]byte("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"),
[]byte("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"),
})
if err != nil {
panic(err)
}
{
n := 0
for _, label := range maxLengthName {
n += len(label) + 1
}
n += 1
if n != 255 {
panic("computeMaxEncodedPayload n != 255")
}
}
queryLimit := uint16(limit)
if int(queryLimit) != limit {
queryLimit = 0xffff
}
query := &Message{
Question: []Question{
{
Name: maxLengthName,
Type: RRTypeTXT,
Class: RRTypeTXT,
},
},
Additional: []RR{
{
Name: Name{},
Type: RRTypeOPT,
Class: queryLimit,
TTL: 0,
Data: []byte{},
},
},
}
resp, _ := responseFor(query, [][]byte{})
resp.Answer = []RR{
{
Name: query.Question[0].Name,
Type: query.Question[0].Type,
Class: query.Question[0].Class,
TTL: responseTTL,
Data: nil,
},
}
low := 0
high := 32768
for low+1 < high {
mid := (low + high) / 2
resp.Answer[0].Data = EncodeRDataTXT(make([]byte, mid))
buf, err := resp.WireFormat()
if err != nil {
panic(err)
}
if len(buf) <= limit {
low = mid
} else {
high = mid
}
}
return low
}
-49
View File
@@ -1,49 +0,0 @@
package internet_test
import (
"testing"
"github.com/xtls/xray-core/common"
. "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/headers/noop"
"github.com/xtls/xray-core/transport/internet/headers/srtp"
"github.com/xtls/xray-core/transport/internet/headers/utp"
"github.com/xtls/xray-core/transport/internet/headers/wechat"
"github.com/xtls/xray-core/transport/internet/headers/wireguard"
)
func TestAllHeadersLoadable(t *testing.T) {
testCases := []struct {
Input interface{}
Size int32
}{
{
Input: new(noop.Config),
Size: 0,
},
{
Input: new(srtp.Config),
Size: 4,
},
{
Input: new(utp.Config),
Size: 4,
},
{
Input: new(wechat.VideoConfig),
Size: 13,
},
{
Input: new(wireguard.WireguardConfig),
Size: 4,
},
}
for _, testCase := range testCases {
header, err := CreatePacketHeader(testCase.Input)
common.Must(err)
if header.Size() != testCase.Size {
t.Error("expected size ", testCase.Size, " but got ", header.Size())
}
}
}
-137
View File
@@ -1,137 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.35.1
// protoc v5.28.2
// source: transport/internet/headers/dns/config.proto
package dns
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
Domain string `protobuf:"bytes,1,opt,name=domain,proto3" json:"domain,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
mi := &file_transport_internet_headers_dns_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_transport_internet_headers_dns_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_transport_internet_headers_dns_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetDomain() string {
if x != nil {
return x.Domain
}
return ""
}
var File_transport_internet_headers_dns_config_proto protoreflect.FileDescriptor
var file_transport_internet_headers_dns_config_proto_rawDesc = []byte{
0x0a, 0x2b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x64, 0x6e, 0x73,
0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x23, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x64,
0x6e, 0x73, 0x22, 0x20, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x16, 0x0a, 0x06,
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f,
0x6d, 0x61, 0x69, 0x6e, 0x42, 0x8b, 0x01, 0x0a, 0x27, 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, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x64, 0x6e, 0x73,
0x50, 0x01, 0x5a, 0x38, 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, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x64, 0x6e, 0x73, 0xaa, 0x02, 0x23, 0x58,
0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x44,
0x4e, 0x53, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_transport_internet_headers_dns_config_proto_rawDescOnce sync.Once
file_transport_internet_headers_dns_config_proto_rawDescData = file_transport_internet_headers_dns_config_proto_rawDesc
)
func file_transport_internet_headers_dns_config_proto_rawDescGZIP() []byte {
file_transport_internet_headers_dns_config_proto_rawDescOnce.Do(func() {
file_transport_internet_headers_dns_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_headers_dns_config_proto_rawDescData)
})
return file_transport_internet_headers_dns_config_proto_rawDescData
}
var file_transport_internet_headers_dns_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_transport_internet_headers_dns_config_proto_goTypes = []any{
(*Config)(nil), // 0: xray.transport.internet.headers.dns.Config
}
var file_transport_internet_headers_dns_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_transport_internet_headers_dns_config_proto_init() }
func file_transport_internet_headers_dns_config_proto_init() {
if File_transport_internet_headers_dns_config_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_transport_internet_headers_dns_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_transport_internet_headers_dns_config_proto_goTypes,
DependencyIndexes: file_transport_internet_headers_dns_config_proto_depIdxs,
MessageInfos: file_transport_internet_headers_dns_config_proto_msgTypes,
}.Build()
File_transport_internet_headers_dns_config_proto = out.File
file_transport_internet_headers_dns_config_proto_rawDesc = nil
file_transport_internet_headers_dns_config_proto_goTypes = nil
file_transport_internet_headers_dns_config_proto_depIdxs = nil
}
@@ -1,12 +0,0 @@
syntax = "proto3";
package xray.transport.internet.headers.dns;
option csharp_namespace = "Xray.Transport.Internet.Headers.DNS";
option go_package = "github.com/xtls/xray-core/transport/internet/headers/dns";
option java_package = "com.xray.transport.internet.headers.dns";
option java_multiple_files = true;
message Config {
string domain = 1;
}
-123
View File
@@ -1,123 +0,0 @@
package dns
import (
"context"
"encoding/binary"
"errors"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/dice"
)
type DNS struct {
header []byte
}
func (d DNS) Size() int32 {
return int32(len(d.header))
}
// Serialize implements PacketHeader.
func (d DNS) Serialize(b []byte) {
copy(b, d.header)
binary.BigEndian.PutUint16(b[0:], dice.RollUint16()) // random transaction ID
}
// NewDNS returns a new DNS instance based on given config.
func NewDNS(ctx context.Context, config interface{}) (interface{}, error) {
var header []byte
header = binary.BigEndian.AppendUint16(header, 0x0000) // Transaction ID
header = binary.BigEndian.AppendUint16(header, 0x0100) // Flags: Standard query
header = binary.BigEndian.AppendUint16(header, 0x0001) // Questions
header = binary.BigEndian.AppendUint16(header, 0x0000) // Answer RRs
header = binary.BigEndian.AppendUint16(header, 0x0000) // Authority RRs
header = binary.BigEndian.AppendUint16(header, 0x0000) // Additional RRs
buf := make([]byte, 0x100)
off1, err := packDomainName(config.(*Config).Domain+".", buf)
if err != nil {
return nil, err
}
header = append(header, buf[:off1]...)
header = binary.BigEndian.AppendUint16(header, 0x0001) // Type: A
header = binary.BigEndian.AppendUint16(header, 0x0001) // Class: IN
return DNS{
header: header,
}, nil
}
// copied from github.com/miekg/dns
func packDomainName(s string, msg []byte) (off1 int, err error) {
off := 0
ls := len(s)
// Each dot ends a segment of the name.
// We trade each dot byte for a length byte.
// Except for escaped dots (\.), which are normal dots.
// There is also a trailing zero.
// Emit sequence of counted strings, chopping at dots.
var (
begin int
bs []byte
)
for i := 0; i < ls; i++ {
var c byte
if bs == nil {
c = s[i]
} else {
c = bs[i]
}
switch c {
case '\\':
if off+1 > len(msg) {
return len(msg), errors.New("buffer size too small")
}
if bs == nil {
bs = []byte(s)
}
copy(bs[i:ls-1], bs[i+1:])
ls--
case '.':
labelLen := i - begin
if labelLen >= 1<<6 { // top two bits of length must be clear
return len(msg), errors.New("bad rdata")
}
// off can already (we're in a loop) be bigger than len(msg)
// this happens when a name isn't fully qualified
if off+1+labelLen > len(msg) {
return len(msg), errors.New("buffer size too small")
}
// The following is covered by the length check above.
msg[off] = byte(labelLen)
if bs == nil {
copy(msg[off+1:], s[begin:i])
} else {
copy(msg[off+1:], bs[begin:i])
}
off += 1 + labelLen
begin = i + 1
default:
}
}
if off < len(msg) {
msg[off] = 0
}
return off + 1, nil
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), NewDNS))
}
@@ -1,187 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.35.1
// protoc v5.28.2
// source: transport/internet/headers/srtp/config.proto
package srtp
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
Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
Padding bool `protobuf:"varint,2,opt,name=padding,proto3" json:"padding,omitempty"`
Extension bool `protobuf:"varint,3,opt,name=extension,proto3" json:"extension,omitempty"`
CsrcCount uint32 `protobuf:"varint,4,opt,name=csrc_count,json=csrcCount,proto3" json:"csrc_count,omitempty"`
Marker bool `protobuf:"varint,5,opt,name=marker,proto3" json:"marker,omitempty"`
PayloadType uint32 `protobuf:"varint,6,opt,name=payload_type,json=payloadType,proto3" json:"payload_type,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
mi := &file_transport_internet_headers_srtp_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_transport_internet_headers_srtp_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_transport_internet_headers_srtp_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetVersion() uint32 {
if x != nil {
return x.Version
}
return 0
}
func (x *Config) GetPadding() bool {
if x != nil {
return x.Padding
}
return false
}
func (x *Config) GetExtension() bool {
if x != nil {
return x.Extension
}
return false
}
func (x *Config) GetCsrcCount() uint32 {
if x != nil {
return x.CsrcCount
}
return 0
}
func (x *Config) GetMarker() bool {
if x != nil {
return x.Marker
}
return false
}
func (x *Config) GetPayloadType() uint32 {
if x != nil {
return x.PayloadType
}
return 0
}
var File_transport_internet_headers_srtp_config_proto protoreflect.FileDescriptor
var file_transport_internet_headers_srtp_config_proto_rawDesc = []byte{
0x0a, 0x2c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x73, 0x72, 0x74,
0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x24,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69,
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e,
0x73, 0x72, 0x74, 0x70, 0x22, 0xb4, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x64,
0x64, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, 0x61, 0x64, 0x64,
0x69, 0x6e, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f,
0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x73, 0x72, 0x63, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18,
0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x63, 0x73, 0x72, 0x63, 0x43, 0x6f, 0x75, 0x6e, 0x74,
0x12, 0x16, 0x0a, 0x06, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08,
0x52, 0x06, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x79, 0x6c,
0x6f, 0x61, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b,
0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x42, 0x8e, 0x01, 0x0a, 0x28,
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, 0x68, 0x65, 0x61, 0x64,
0x65, 0x72, 0x73, 0x2e, 0x73, 0x72, 0x74, 0x70, 0x50, 0x01, 0x5a, 0x39, 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, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73,
0x2f, 0x73, 0x72, 0x74, 0x70, 0xaa, 0x02, 0x24, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61,
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x53, 0x72, 0x74, 0x70, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
}
var (
file_transport_internet_headers_srtp_config_proto_rawDescOnce sync.Once
file_transport_internet_headers_srtp_config_proto_rawDescData = file_transport_internet_headers_srtp_config_proto_rawDesc
)
func file_transport_internet_headers_srtp_config_proto_rawDescGZIP() []byte {
file_transport_internet_headers_srtp_config_proto_rawDescOnce.Do(func() {
file_transport_internet_headers_srtp_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_headers_srtp_config_proto_rawDescData)
})
return file_transport_internet_headers_srtp_config_proto_rawDescData
}
var file_transport_internet_headers_srtp_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_transport_internet_headers_srtp_config_proto_goTypes = []any{
(*Config)(nil), // 0: xray.transport.internet.headers.srtp.Config
}
var file_transport_internet_headers_srtp_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_transport_internet_headers_srtp_config_proto_init() }
func file_transport_internet_headers_srtp_config_proto_init() {
if File_transport_internet_headers_srtp_config_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_transport_internet_headers_srtp_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_transport_internet_headers_srtp_config_proto_goTypes,
DependencyIndexes: file_transport_internet_headers_srtp_config_proto_depIdxs,
MessageInfos: file_transport_internet_headers_srtp_config_proto_msgTypes,
}.Build()
File_transport_internet_headers_srtp_config_proto = out.File
file_transport_internet_headers_srtp_config_proto_rawDesc = nil
file_transport_internet_headers_srtp_config_proto_goTypes = nil
file_transport_internet_headers_srtp_config_proto_depIdxs = nil
}
@@ -1,16 +0,0 @@
syntax = "proto3";
package xray.transport.internet.headers.srtp;
option csharp_namespace = "Xray.Transport.Internet.Headers.Srtp";
option go_package = "github.com/xtls/xray-core/transport/internet/headers/srtp";
option java_package = "com.xray.transport.internet.headers.srtp";
option java_multiple_files = true;
message Config {
uint32 version = 1;
bool padding = 2;
bool extension = 3;
uint32 csrc_count = 4;
bool marker = 5;
uint32 payload_type = 6;
}
-37
View File
@@ -1,37 +0,0 @@
package srtp
import (
"context"
"encoding/binary"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/dice"
)
type SRTP struct {
header uint16
number uint16
}
func (*SRTP) Size() int32 {
return 4
}
// Serialize implements PacketHeader.
func (s *SRTP) Serialize(b []byte) {
s.number++
binary.BigEndian.PutUint16(b, s.header)
binary.BigEndian.PutUint16(b[2:], s.number)
}
// New returns a new SRTP instance based on the given config.
func New(ctx context.Context, config interface{}) (interface{}, error) {
return &SRTP{
header: 0xB5E8,
number: dice.RollUint16(),
}, nil
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), New))
}
@@ -1,27 +0,0 @@
package srtp_test
import (
"context"
"testing"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
. "github.com/xtls/xray-core/transport/internet/headers/srtp"
)
func TestSRTPWrite(t *testing.T) {
content := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g'}
srtpRaw, err := New(context.Background(), &Config{})
common.Must(err)
srtp := srtpRaw.(*SRTP)
payload := buf.New()
srtp.Serialize(payload.Extend(srtp.Size()))
payload.Write(content)
expectedLen := int32(len(content)) + srtp.Size()
if payload.Len() != expectedLen {
t.Error("expected ", expectedLen, " of bytes, but got ", payload.Len())
}
}
-127
View File
@@ -1,127 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.35.1
// protoc v5.28.2
// source: transport/internet/headers/tls/config.proto
package tls
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 PacketConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *PacketConfig) Reset() {
*x = PacketConfig{}
mi := &file_transport_internet_headers_tls_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PacketConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PacketConfig) ProtoMessage() {}
func (x *PacketConfig) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_headers_tls_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 PacketConfig.ProtoReflect.Descriptor instead.
func (*PacketConfig) Descriptor() ([]byte, []int) {
return file_transport_internet_headers_tls_config_proto_rawDescGZIP(), []int{0}
}
var File_transport_internet_headers_tls_config_proto protoreflect.FileDescriptor
var file_transport_internet_headers_tls_config_proto_rawDesc = []byte{
0x0a, 0x2b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x74, 0x6c, 0x73,
0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x23, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x74,
0x6c, 0x73, 0x22, 0x0e, 0x0a, 0x0c, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x42, 0x8b, 0x01, 0x0a, 0x27, 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, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x74, 0x6c, 0x73, 0x50, 0x01,
0x5a, 0x38, 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, 0x68,
0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x74, 0x6c, 0x73, 0xaa, 0x02, 0x23, 0x58, 0x72, 0x61,
0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x65, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x54, 0x6c, 0x73,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_transport_internet_headers_tls_config_proto_rawDescOnce sync.Once
file_transport_internet_headers_tls_config_proto_rawDescData = file_transport_internet_headers_tls_config_proto_rawDesc
)
func file_transport_internet_headers_tls_config_proto_rawDescGZIP() []byte {
file_transport_internet_headers_tls_config_proto_rawDescOnce.Do(func() {
file_transport_internet_headers_tls_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_headers_tls_config_proto_rawDescData)
})
return file_transport_internet_headers_tls_config_proto_rawDescData
}
var file_transport_internet_headers_tls_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_transport_internet_headers_tls_config_proto_goTypes = []any{
(*PacketConfig)(nil), // 0: xray.transport.internet.headers.tls.PacketConfig
}
var file_transport_internet_headers_tls_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_transport_internet_headers_tls_config_proto_init() }
func file_transport_internet_headers_tls_config_proto_init() {
if File_transport_internet_headers_tls_config_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_transport_internet_headers_tls_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_transport_internet_headers_tls_config_proto_goTypes,
DependencyIndexes: file_transport_internet_headers_tls_config_proto_depIdxs,
MessageInfos: file_transport_internet_headers_tls_config_proto_msgTypes,
}.Build()
File_transport_internet_headers_tls_config_proto = out.File
file_transport_internet_headers_tls_config_proto_rawDesc = nil
file_transport_internet_headers_tls_config_proto_goTypes = nil
file_transport_internet_headers_tls_config_proto_depIdxs = nil
}
@@ -1,9 +0,0 @@
syntax = "proto3";
package xray.transport.internet.headers.tls;
option csharp_namespace = "Xray.Transport.Internet.Headers.Tls";
option go_package = "github.com/xtls/xray-core/transport/internet/headers/tls";
option java_package = "com.xray.transport.internet.headers.tls";
option java_multiple_files = true;
message PacketConfig {}
-55
View File
@@ -1,55 +0,0 @@
package tls
import (
"context"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/dice"
)
// DTLS writes header as DTLS. See https://tools.ietf.org/html/rfc6347
type DTLS struct {
epoch uint16
length uint16
sequence uint32
}
// Size implements PacketHeader.
func (*DTLS) Size() int32 {
return 1 + 2 + 2 + 6 + 2
}
// Serialize implements PacketHeader.
func (d *DTLS) Serialize(b []byte) {
b[0] = 23 // application data
b[1] = 254
b[2] = 253
b[3] = byte(d.epoch >> 8)
b[4] = byte(d.epoch)
b[5] = 0
b[6] = 0
b[7] = byte(d.sequence >> 24)
b[8] = byte(d.sequence >> 16)
b[9] = byte(d.sequence >> 8)
b[10] = byte(d.sequence)
d.sequence++
b[11] = byte(d.length >> 8)
b[12] = byte(d.length)
d.length += 17
if d.length > 100 {
d.length -= 50
}
}
// New creates a new UTP header for the given config.
func New(ctx context.Context, config interface{}) (interface{}, error) {
return &DTLS{
epoch: dice.RollUint16(),
sequence: 0,
length: 17,
}, nil
}
func init() {
common.Must(common.RegisterConfig((*PacketConfig)(nil), New))
}
@@ -1,26 +0,0 @@
package tls_test
import (
"context"
"testing"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
. "github.com/xtls/xray-core/transport/internet/headers/tls"
)
func TestDTLSWrite(t *testing.T) {
content := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g'}
dtlsRaw, err := New(context.Background(), &PacketConfig{})
common.Must(err)
dtls := dtlsRaw.(*DTLS)
payload := buf.New()
dtls.Serialize(payload.Extend(dtls.Size()))
payload.Write(content)
if payload.Len() != int32(len(content))+dtls.Size() {
t.Error("payload len: ", payload.Len(), " want ", int32(len(content))+dtls.Size())
}
}
-137
View File
@@ -1,137 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.35.1
// protoc v5.28.2
// source: transport/internet/headers/utp/config.proto
package utp
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
Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
mi := &file_transport_internet_headers_utp_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_transport_internet_headers_utp_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_transport_internet_headers_utp_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetVersion() uint32 {
if x != nil {
return x.Version
}
return 0
}
var File_transport_internet_headers_utp_config_proto protoreflect.FileDescriptor
var file_transport_internet_headers_utp_config_proto_rawDesc = []byte{
0x0a, 0x2b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x75, 0x74, 0x70,
0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x23, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x75,
0x74, 0x70, 0x22, 0x22, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07,
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x8b, 0x01, 0x0a, 0x27, 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, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x75,
0x74, 0x70, 0x50, 0x01, 0x5a, 0x38, 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, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x75, 0x74, 0x70, 0xaa, 0x02,
0x23, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e,
0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73,
0x2e, 0x55, 0x74, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_transport_internet_headers_utp_config_proto_rawDescOnce sync.Once
file_transport_internet_headers_utp_config_proto_rawDescData = file_transport_internet_headers_utp_config_proto_rawDesc
)
func file_transport_internet_headers_utp_config_proto_rawDescGZIP() []byte {
file_transport_internet_headers_utp_config_proto_rawDescOnce.Do(func() {
file_transport_internet_headers_utp_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_headers_utp_config_proto_rawDescData)
})
return file_transport_internet_headers_utp_config_proto_rawDescData
}
var file_transport_internet_headers_utp_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_transport_internet_headers_utp_config_proto_goTypes = []any{
(*Config)(nil), // 0: xray.transport.internet.headers.utp.Config
}
var file_transport_internet_headers_utp_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_transport_internet_headers_utp_config_proto_init() }
func file_transport_internet_headers_utp_config_proto_init() {
if File_transport_internet_headers_utp_config_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_transport_internet_headers_utp_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_transport_internet_headers_utp_config_proto_goTypes,
DependencyIndexes: file_transport_internet_headers_utp_config_proto_depIdxs,
MessageInfos: file_transport_internet_headers_utp_config_proto_msgTypes,
}.Build()
File_transport_internet_headers_utp_config_proto = out.File
file_transport_internet_headers_utp_config_proto_rawDesc = nil
file_transport_internet_headers_utp_config_proto_goTypes = nil
file_transport_internet_headers_utp_config_proto_depIdxs = nil
}
@@ -1,11 +0,0 @@
syntax = "proto3";
package xray.transport.internet.headers.utp;
option csharp_namespace = "Xray.Transport.Internet.Headers.Utp";
option go_package = "github.com/xtls/xray-core/transport/internet/headers/utp";
option java_package = "com.xray.transport.internet.headers.utp";
option java_multiple_files = true;
message Config {
uint32 version = 1;
}
-39
View File
@@ -1,39 +0,0 @@
package utp
import (
"context"
"encoding/binary"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/dice"
)
type UTP struct {
header byte
extension byte
connectionID uint16
}
func (*UTP) Size() int32 {
return 4
}
// Serialize implements PacketHeader.
func (u *UTP) Serialize(b []byte) {
binary.BigEndian.PutUint16(b, u.connectionID)
b[2] = u.header
b[3] = u.extension
}
// New creates a new UTP header for the given config.
func New(ctx context.Context, config interface{}) (interface{}, error) {
return &UTP{
header: 1,
extension: 0,
connectionID: dice.RollUint16(),
}, nil
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), New))
}
@@ -1,26 +0,0 @@
package utp_test
import (
"context"
"testing"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
. "github.com/xtls/xray-core/transport/internet/headers/utp"
)
func TestUTPWrite(t *testing.T) {
content := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g'}
utpRaw, err := New(context.Background(), &Config{})
common.Must(err)
utp := utpRaw.(*UTP)
payload := buf.New()
utp.Serialize(payload.Extend(utp.Size()))
payload.Write(content)
if payload.Len() != int32(len(content))+utp.Size() {
t.Error("unexpected payload length: ", payload.Len())
}
}
@@ -1,128 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.35.1
// protoc v5.28.2
// source: transport/internet/headers/wechat/config.proto
package wechat
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 VideoConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *VideoConfig) Reset() {
*x = VideoConfig{}
mi := &file_transport_internet_headers_wechat_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *VideoConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*VideoConfig) ProtoMessage() {}
func (x *VideoConfig) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_headers_wechat_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 VideoConfig.ProtoReflect.Descriptor instead.
func (*VideoConfig) Descriptor() ([]byte, []int) {
return file_transport_internet_headers_wechat_config_proto_rawDescGZIP(), []int{0}
}
var File_transport_internet_headers_wechat_config_proto protoreflect.FileDescriptor
var file_transport_internet_headers_wechat_config_proto_rawDesc = []byte{
0x0a, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x77, 0x65, 0x63,
0x68, 0x61, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x12, 0x26, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74,
0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,
0x73, 0x2e, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x22, 0x0d, 0x0a, 0x0b, 0x56, 0x69, 0x64, 0x65,
0x6f, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x94, 0x01, 0x0a, 0x2a, 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, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e,
0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x50, 0x01, 0x5a, 0x3b, 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, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x77,
0x65, 0x63, 0x68, 0x61, 0x74, 0xaa, 0x02, 0x26, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61,
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x57, 0x65, 0x63, 0x68, 0x61, 0x74, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_transport_internet_headers_wechat_config_proto_rawDescOnce sync.Once
file_transport_internet_headers_wechat_config_proto_rawDescData = file_transport_internet_headers_wechat_config_proto_rawDesc
)
func file_transport_internet_headers_wechat_config_proto_rawDescGZIP() []byte {
file_transport_internet_headers_wechat_config_proto_rawDescOnce.Do(func() {
file_transport_internet_headers_wechat_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_headers_wechat_config_proto_rawDescData)
})
return file_transport_internet_headers_wechat_config_proto_rawDescData
}
var file_transport_internet_headers_wechat_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_transport_internet_headers_wechat_config_proto_goTypes = []any{
(*VideoConfig)(nil), // 0: xray.transport.internet.headers.wechat.VideoConfig
}
var file_transport_internet_headers_wechat_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_transport_internet_headers_wechat_config_proto_init() }
func file_transport_internet_headers_wechat_config_proto_init() {
if File_transport_internet_headers_wechat_config_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_transport_internet_headers_wechat_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_transport_internet_headers_wechat_config_proto_goTypes,
DependencyIndexes: file_transport_internet_headers_wechat_config_proto_depIdxs,
MessageInfos: file_transport_internet_headers_wechat_config_proto_msgTypes,
}.Build()
File_transport_internet_headers_wechat_config_proto = out.File
file_transport_internet_headers_wechat_config_proto_rawDesc = nil
file_transport_internet_headers_wechat_config_proto_goTypes = nil
file_transport_internet_headers_wechat_config_proto_depIdxs = nil
}
@@ -1,9 +0,0 @@
syntax = "proto3";
package xray.transport.internet.headers.wechat;
option csharp_namespace = "Xray.Transport.Internet.Headers.Wechat";
option go_package = "github.com/xtls/xray-core/transport/internet/headers/wechat";
option java_package = "com.xray.transport.internet.headers.wechat";
option java_multiple_files = true;
message VideoConfig {}
@@ -1,43 +0,0 @@
package wechat
import (
"context"
"encoding/binary"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/dice"
)
type VideoChat struct {
sn uint32
}
func (vc *VideoChat) Size() int32 {
return 13
}
// Serialize implements PacketHeader.
func (vc *VideoChat) Serialize(b []byte) {
vc.sn++
b[0] = 0xa1
b[1] = 0x08
binary.BigEndian.PutUint32(b[2:], vc.sn) // b[2:6]
b[6] = 0x00
b[7] = 0x10
b[8] = 0x11
b[9] = 0x18
b[10] = 0x30
b[11] = 0x22
b[12] = 0x30
}
// NewVideoChat returns a new VideoChat instance based on given config.
func NewVideoChat(ctx context.Context, config interface{}) (interface{}, error) {
return &VideoChat{
sn: uint32(dice.RollUint16()),
}, nil
}
func init() {
common.Must(common.RegisterConfig((*VideoConfig)(nil), NewVideoChat))
}
@@ -1,24 +0,0 @@
package wechat_test
import (
"context"
"testing"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
. "github.com/xtls/xray-core/transport/internet/headers/wechat"
)
func TestUTPWrite(t *testing.T) {
videoRaw, err := NewVideoChat(context.Background(), &VideoConfig{})
common.Must(err)
video := videoRaw.(*VideoChat)
payload := buf.New()
video.Serialize(payload.Extend(video.Size()))
if payload.Len() != video.Size() {
t.Error("expected payload size ", video.Size(), " but got ", payload.Len())
}
}
@@ -1,129 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.35.1
// protoc v5.28.2
// source: transport/internet/headers/wireguard/config.proto
package wireguard
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 WireguardConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *WireguardConfig) Reset() {
*x = WireguardConfig{}
mi := &file_transport_internet_headers_wireguard_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *WireguardConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*WireguardConfig) ProtoMessage() {}
func (x *WireguardConfig) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_headers_wireguard_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 WireguardConfig.ProtoReflect.Descriptor instead.
func (*WireguardConfig) Descriptor() ([]byte, []int) {
return file_transport_internet_headers_wireguard_config_proto_rawDescGZIP(), []int{0}
}
var File_transport_internet_headers_wireguard_config_proto protoreflect.FileDescriptor
var file_transport_internet_headers_wireguard_config_proto_rawDesc = []byte{
0x0a, 0x31, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x77, 0x69, 0x72,
0x65, 0x67, 0x75, 0x61, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x12, 0x29, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,
0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61,
0x64, 0x65, 0x72, 0x73, 0x2e, 0x77, 0x69, 0x72, 0x65, 0x67, 0x75, 0x61, 0x72, 0x64, 0x22, 0x11,
0x0a, 0x0f, 0x57, 0x69, 0x72, 0x65, 0x67, 0x75, 0x61, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x42, 0x9d, 0x01, 0x0a, 0x2d, 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, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x77, 0x69, 0x72, 0x65, 0x67, 0x75,
0x61, 0x72, 0x64, 0x50, 0x01, 0x5a, 0x3e, 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, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x77, 0x69, 0x72, 0x65,
0x67, 0x75, 0x61, 0x72, 0x64, 0xaa, 0x02, 0x29, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61,
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x57, 0x69, 0x72, 0x65, 0x67, 0x75, 0x61, 0x72,
0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_transport_internet_headers_wireguard_config_proto_rawDescOnce sync.Once
file_transport_internet_headers_wireguard_config_proto_rawDescData = file_transport_internet_headers_wireguard_config_proto_rawDesc
)
func file_transport_internet_headers_wireguard_config_proto_rawDescGZIP() []byte {
file_transport_internet_headers_wireguard_config_proto_rawDescOnce.Do(func() {
file_transport_internet_headers_wireguard_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_headers_wireguard_config_proto_rawDescData)
})
return file_transport_internet_headers_wireguard_config_proto_rawDescData
}
var file_transport_internet_headers_wireguard_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_transport_internet_headers_wireguard_config_proto_goTypes = []any{
(*WireguardConfig)(nil), // 0: xray.transport.internet.headers.wireguard.WireguardConfig
}
var file_transport_internet_headers_wireguard_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_transport_internet_headers_wireguard_config_proto_init() }
func file_transport_internet_headers_wireguard_config_proto_init() {
if File_transport_internet_headers_wireguard_config_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_transport_internet_headers_wireguard_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_transport_internet_headers_wireguard_config_proto_goTypes,
DependencyIndexes: file_transport_internet_headers_wireguard_config_proto_depIdxs,
MessageInfos: file_transport_internet_headers_wireguard_config_proto_msgTypes,
}.Build()
File_transport_internet_headers_wireguard_config_proto = out.File
file_transport_internet_headers_wireguard_config_proto_rawDesc = nil
file_transport_internet_headers_wireguard_config_proto_goTypes = nil
file_transport_internet_headers_wireguard_config_proto_depIdxs = nil
}
@@ -1,9 +0,0 @@
syntax = "proto3";
package xray.transport.internet.headers.wireguard;
option csharp_namespace = "Xray.Transport.Internet.Headers.Wireguard";
option go_package = "github.com/xtls/xray-core/transport/internet/headers/wireguard";
option java_package = "com.xray.transport.internet.headers.wireguard";
option java_multiple_files = true;
message WireguardConfig {}
@@ -1,30 +0,0 @@
package wireguard
import (
"context"
"github.com/xtls/xray-core/common"
)
type Wireguard struct{}
func (Wireguard) Size() int32 {
return 4
}
// Serialize implements PacketHeader.
func (Wireguard) Serialize(b []byte) {
b[0] = 0x04
b[1] = 0x00
b[2] = 0x00
b[3] = 0x00
}
// NewWireguard returns a new VideoChat instance based on given config.
func NewWireguard(ctx context.Context, config interface{}) (interface{}, error) {
return Wireguard{}, nil
}
func init() {
common.Must(common.RegisterConfig((*WireguardConfig)(nil), NewWireguard))
}
+2
View File
@@ -176,6 +176,7 @@ func (c *client) dial() error {
} }
pktConn, err = udphop.NewUDPHopPacketConn(addr, c.config.IntervalMin, c.config.IntervalMax, c.udphopDialer, pktConn, index) pktConn, err = udphop.NewUDPHopPacketConn(addr, c.config.IntervalMin, c.config.IntervalMax, c.udphopDialer, pktConn, index)
if err != nil { if err != nil {
raw.Close()
return errors.New("udphop err").Base(err) return errors.New("udphop err").Base(err)
} }
} }
@@ -183,6 +184,7 @@ func (c *client) dial() error {
if c.udpmaskManager != nil { if c.udpmaskManager != nil {
pktConn, err = c.udpmaskManager.WrapPacketConnClient(pktConn) pktConn, err = c.udpmaskManager.WrapPacketConnClient(pktConn)
if err != nil { if err != nil {
raw.Close()
return errors.New("mask err").Base(err) return errors.New("mask err").Base(err)
} }
} }
+9 -31
View File
@@ -1,8 +1,6 @@
package kcp package kcp
import ( import (
"crypto/cipher"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
) )
@@ -48,32 +46,12 @@ func (c *Config) GetWriteBufferSize() uint32 {
} }
// GetReadBufferSize returns the size of ReadBuffer in bytes. // GetReadBufferSize returns the size of ReadBuffer in bytes.
func (c *Config) GetReadBufferSize() uint32 { // func (c *Config) GetReadBufferSize() uint32 {
if c == nil || c.ReadBuffer == nil { // if c == nil || c.ReadBuffer == nil {
return 2 * 1024 * 1024 // return 2 * 1024 * 1024
} // }
return c.ReadBuffer.Size // return c.ReadBuffer.Size
} // }
// GetSecurity returns the security settings.
func (c *Config) GetSecurity() (cipher.AEAD, error) {
if c.Seed != nil {
return NewAEADAESGCMBasedOnSeed(c.Seed.Seed), nil
}
return NewSimpleAuthenticator(), nil
}
func (c *Config) GetPackerHeader() (internet.PacketHeader, error) {
if c.HeaderConfig != nil {
rawConfig, err := c.HeaderConfig.GetInstance()
if err != nil {
return nil, err
}
return internet.CreatePacketHeader(rawConfig)
}
return nil, nil
}
func (c *Config) GetSendingInFlightSize() uint32 { func (c *Config) GetSendingInFlightSize() uint32 {
size := c.GetUplinkCapacityValue() * 1024 * 1024 / c.GetMTUValue() / (1000 / c.GetTTIValue()) size := c.GetUplinkCapacityValue() * 1024 * 1024 / c.GetMTUValue() / (1000 / c.GetTTIValue())
@@ -95,9 +73,9 @@ func (c *Config) GetReceivingInFlightSize() uint32 {
return size return size
} }
func (c *Config) GetReceivingBufferSize() uint32 { // func (c *Config) GetReceivingBufferSize() uint32 {
return c.GetReadBufferSize() / c.GetMTUValue() // return c.GetReadBufferSize() / c.GetMTUValue()
} // }
func init() { func init() {
common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} { common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {
+2 -2
View File
@@ -204,7 +204,7 @@ type Connection struct {
} }
// NewConnection create a new KCP connection between local and remote. // NewConnection create a new KCP connection between local and remote.
func NewConnection(meta ConnMetadata, writer PacketWriter, closer io.Closer, config *Config) *Connection { func NewConnection(meta ConnMetadata, writer io.Writer, closer io.Closer, config *Config) *Connection {
errors.LogInfo(context.Background(), "#", meta.Conversation, " creating connection to ", meta.RemoteAddr) errors.LogInfo(context.Background(), "#", meta.Conversation, " creating connection to ", meta.RemoteAddr)
conn := &Connection{ conn := &Connection{
@@ -215,7 +215,7 @@ func NewConnection(meta ConnMetadata, writer PacketWriter, closer io.Closer, con
dataOutput: signal.NewNotifier(), dataOutput: signal.NewNotifier(),
Config: config, Config: config,
output: NewRetryableWriter(NewSegmentWriter(writer)), output: NewRetryableWriter(NewSegmentWriter(writer)),
mss: config.GetMTUValue() - uint32(writer.Overhead()) - DataSegmentOverhead, mss: config.GetMTUValue() - DataSegmentOverhead,
roundTrip: &RoundTripInfo{ roundTrip: &RoundTripInfo{
rto: 100, rto: 100,
minRtt: config.GetTTIValue(), minRtt: config.GetTTIValue(),
+1 -3
View File
@@ -16,9 +16,7 @@ func (NoOpCloser) Close() error {
} }
func TestConnectionReadTimeout(t *testing.T) { func TestConnectionReadTimeout(t *testing.T) {
conn := NewConnection(ConnMetadata{Conversation: 1}, &KCPPacketWriter{ conn := NewConnection(ConnMetadata{Conversation: 1}, buf.DiscardBytes, NoOpCloser(0), &Config{})
Writer: buf.DiscardBytes,
}, NoOpCloser(0), &Config{})
conn.SetReadDeadline(time.Now().Add(time.Second)) conn.SetReadDeadline(time.Now().Add(time.Second))
b := make([]byte, 1024) b := make([]byte, 1024)
-77
View File
@@ -1,77 +0,0 @@
package kcp
import (
"crypto/cipher"
"encoding/binary"
"hash/fnv"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
)
// SimpleAuthenticator is a legacy AEAD used for KCP encryption.
type SimpleAuthenticator struct{}
// NewSimpleAuthenticator creates a new SimpleAuthenticator
func NewSimpleAuthenticator() cipher.AEAD {
return &SimpleAuthenticator{}
}
// NonceSize implements cipher.AEAD.NonceSize().
func (*SimpleAuthenticator) NonceSize() int {
return 0
}
// Overhead implements cipher.AEAD.NonceSize().
func (*SimpleAuthenticator) Overhead() int {
return 6
}
// Seal implements cipher.AEAD.Seal().
func (a *SimpleAuthenticator) Seal(dst, nonce, plain, extra []byte) []byte {
dst = append(dst, 0, 0, 0, 0, 0, 0) // 4 bytes for hash, and then 2 bytes for length
binary.BigEndian.PutUint16(dst[4:], uint16(len(plain)))
dst = append(dst, plain...)
fnvHash := fnv.New32a()
common.Must2(fnvHash.Write(dst[4:]))
fnvHash.Sum(dst[:0])
dstLen := len(dst)
xtra := 4 - dstLen%4
if xtra != 4 {
dst = append(dst, make([]byte, xtra)...)
}
xorfwd(dst)
if xtra != 4 {
dst = dst[:dstLen]
}
return dst
}
// Open implements cipher.AEAD.Open().
func (a *SimpleAuthenticator) Open(dst, nonce, cipherText, extra []byte) ([]byte, error) {
dst = append(dst, cipherText...)
dstLen := len(dst)
xtra := 4 - dstLen%4
if xtra != 4 {
dst = append(dst, make([]byte, xtra)...)
}
xorbkd(dst)
if xtra != 4 {
dst = dst[:dstLen]
}
fnvHash := fnv.New32a()
common.Must2(fnvHash.Write(dst[4:]))
if binary.BigEndian.Uint32(dst[:4]) != fnvHash.Sum32() {
return nil, errors.New("invalid auth")
}
length := binary.BigEndian.Uint16(dst[4:6])
if len(dst)-6 != int(length) {
return nil, errors.New("invalid auth")
}
return dst[6:], nil
}
-37
View File
@@ -1,37 +0,0 @@
package kcp_test
import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/xtls/xray-core/common"
. "github.com/xtls/xray-core/transport/internet/kcp"
)
func TestSimpleAuthenticator(t *testing.T) {
cache := make([]byte, 512)
payload := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g'}
auth := NewSimpleAuthenticator()
b := auth.Seal(cache[:0], nil, payload, nil)
c, err := auth.Open(cache[:0], nil, b, nil)
common.Must(err)
if r := cmp.Diff(c, payload); r != "" {
t.Error(r)
}
}
func TestSimpleAuthenticator2(t *testing.T) {
cache := make([]byte, 512)
payload := []byte{'a', 'b'}
auth := NewSimpleAuthenticator()
b := auth.Seal(cache[:0], nil, payload, nil)
c, err := auth.Open(cache[:0], nil, b, nil)
common.Must(err)
if r := cmp.Diff(c, payload); r != "" {
t.Error(r)
}
}
-13
View File
@@ -1,13 +0,0 @@
package kcp
import (
"crypto/cipher"
"crypto/sha256"
"github.com/xtls/xray-core/common/crypto"
)
func NewAEADAESGCMBasedOnSeed(seed string) cipher.AEAD {
hashedSeed := sha256.Sum256([]byte(seed))
return crypto.NewAesGcm(hashedSeed[:16])
}
+18 -18
View File
@@ -54,32 +54,32 @@ func DialKCP(ctx context.Context, dest net.Destination, streamSettings *internet
return nil, errors.New("failed to dial to dest: ", err).AtWarning().Base(err) return nil, errors.New("failed to dial to dest: ", err).AtWarning().Base(err)
} }
wrapper, ok := rawConn.(*internet.PacketConnWrapper)
if !ok {
rawConn.Close()
return nil, errors.New("raw is not PacketConnWrapper")
}
raw := wrapper.Conn
if streamSettings.UdpmaskManager != nil {
wrapper.Conn, err = streamSettings.UdpmaskManager.WrapPacketConnClient(raw)
if err != nil {
raw.Close()
return nil, errors.New("mask err").Base(err)
}
}
kcpSettings := streamSettings.ProtocolSettings.(*Config) kcpSettings := streamSettings.ProtocolSettings.(*Config)
header, err := kcpSettings.GetPackerHeader() reader := &KCPPacketReader{}
if err != nil {
return nil, errors.New("failed to create packet header").Base(err)
}
security, err := kcpSettings.GetSecurity()
if err != nil {
return nil, errors.New("failed to create security").Base(err)
}
reader := &KCPPacketReader{
Header: header,
Security: security,
}
writer := &KCPPacketWriter{
Header: header,
Security: security,
Writer: rawConn,
}
conv := uint16(atomic.AddUint32(&globalConv, 1)) conv := uint16(atomic.AddUint32(&globalConv, 1))
session := NewConnection(ConnMetadata{ session := NewConnection(ConnMetadata{
LocalAddr: rawConn.LocalAddr(), LocalAddr: rawConn.LocalAddr(),
RemoteAddr: rawConn.RemoteAddr(), RemoteAddr: rawConn.RemoteAddr(),
Conversation: conv, Conversation: conv,
}, writer, rawConn, kcpSettings) }, rawConn, rawConn, kcpSettings)
go fetchInput(ctx, rawConn, reader, session) go fetchInput(ctx, rawConn, reader, session)
+1 -76
View File
@@ -1,48 +1,12 @@
package kcp package kcp
import (
"crypto/cipher"
"crypto/rand"
"io"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/transport/internet"
)
type PacketReader interface { type PacketReader interface {
Read([]byte) []Segment Read([]byte) []Segment
} }
type PacketWriter interface { type KCPPacketReader struct{}
Overhead() int
io.Writer
}
type KCPPacketReader struct {
Security cipher.AEAD
Header internet.PacketHeader
}
func (r *KCPPacketReader) Read(b []byte) []Segment { func (r *KCPPacketReader) Read(b []byte) []Segment {
if r.Header != nil {
if int32(len(b)) <= r.Header.Size() {
return nil
}
b = b[r.Header.Size():]
}
if r.Security != nil {
nonceSize := r.Security.NonceSize()
overhead := r.Security.Overhead()
if len(b) <= nonceSize+overhead {
return nil
}
out, err := r.Security.Open(b[nonceSize:nonceSize], b[:nonceSize], b[nonceSize:], nil)
if err != nil {
return nil
}
b = out
}
var result []Segment var result []Segment
for len(b) > 0 { for len(b) > 0 {
seg, x := ReadSegment(b) seg, x := ReadSegment(b)
@@ -54,42 +18,3 @@ func (r *KCPPacketReader) Read(b []byte) []Segment {
} }
return result return result
} }
type KCPPacketWriter struct {
Header internet.PacketHeader
Security cipher.AEAD
Writer io.Writer
}
func (w *KCPPacketWriter) Overhead() int {
overhead := 0
if w.Header != nil {
overhead += int(w.Header.Size())
}
if w.Security != nil {
overhead += w.Security.Overhead()
}
return overhead
}
func (w *KCPPacketWriter) Write(b []byte) (int, error) {
bb := buf.StackNew()
defer bb.Release()
if w.Header != nil {
w.Header.Serialize(bb.Extend(w.Header.Size()))
}
if w.Security != nil {
nonceSize := w.Security.NonceSize()
common.Must2(bb.ReadFullFrom(rand.Reader, int32(nonceSize)))
nonce := bb.BytesFrom(int32(-nonceSize))
encrypted := bb.Extend(int32(w.Security.Overhead() + len(b)))
w.Security.Seal(encrypted[:0], nonce, b, nil)
} else {
bb.Write(b)
}
_, err := w.Writer.Write(bb.Bytes())
return len(b), err
}
+1 -3
View File
@@ -7,9 +7,7 @@ import (
) )
func TestKCPPacketReader(t *testing.T) { func TestKCPPacketReader(t *testing.T) {
reader := KCPPacketReader{ reader := KCPPacketReader{}
Security: &SimpleAuthenticator{},
}
testCases := []struct { testCases := []struct {
Input []byte Input []byte
+3 -22
View File
@@ -2,7 +2,6 @@ package kcp
import ( import (
"context" "context"
"crypto/cipher"
gotls "crypto/tls" gotls "crypto/tls"
"sync" "sync"
@@ -30,28 +29,14 @@ type Listener struct {
tlsConfig *gotls.Config tlsConfig *gotls.Config
config *Config config *Config
reader PacketReader reader PacketReader
header internet.PacketHeader
security cipher.AEAD
addConn internet.ConnHandler addConn internet.ConnHandler
} }
func NewListener(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, addConn internet.ConnHandler) (*Listener, error) { func NewListener(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, addConn internet.ConnHandler) (*Listener, error) {
kcpSettings := streamSettings.ProtocolSettings.(*Config) kcpSettings := streamSettings.ProtocolSettings.(*Config)
header, err := kcpSettings.GetPackerHeader()
if err != nil {
return nil, errors.New("failed to create packet header").Base(err).AtError()
}
security, err := kcpSettings.GetSecurity()
if err != nil {
return nil, errors.New("failed to create security").Base(err).AtError()
}
l := &Listener{ l := &Listener{
header: header, reader: &KCPPacketReader{},
security: security,
reader: &KCPPacketReader{
Header: header,
Security: security,
},
sessions: make(map[ConnectionID]*Connection), sessions: make(map[ConnectionID]*Connection),
config: kcpSettings, config: kcpSettings,
addConn: addConn, addConn: addConn,
@@ -124,11 +109,7 @@ func (l *Listener) OnReceive(payload *buf.Buffer, src net.Destination) {
LocalAddr: localAddr, LocalAddr: localAddr,
RemoteAddr: remoteAddr, RemoteAddr: remoteAddr,
Conversation: conv, Conversation: conv,
}, &KCPPacketWriter{ }, writer, writer, l.config)
Header: l.header,
Security: l.security,
Writer: writer,
}, writer, l.config)
var netConn stat.Connection = conn var netConn stat.Connection = conn
if l.tlsConfig != nil { if l.tlsConfig != nil {
netConn = tls.Server(conn, l.tlsConfig) netConn = tls.Server(conn, l.tlsConfig)
+31 -7
View File
@@ -25,7 +25,8 @@ func HubReceiveOriginalDestination(r bool) HubOption {
} }
type Hub struct { type Hub struct {
conn *net.UDPConn conn net.PacketConn
udpConn *net.UDPConn
cache chan *udp.Packet cache chan *udp.Packet
capacity int capacity int
recvOrigDest bool recvOrigDest bool
@@ -56,15 +57,27 @@ func ListenUDP(ctx context.Context, address net.Address, port net.Port, streamSe
hub.recvOrigDest = true hub.recvOrigDest = true
} }
udpConn, err := internet.ListenSystemPacket(ctx, &net.UDPAddr{ var err error
hub.conn, err = internet.ListenSystemPacket(ctx, &net.UDPAddr{
IP: address.IP(), IP: address.IP(),
Port: int(port), Port: int(port),
}, sockopt) }, sockopt)
if err != nil { if err != nil {
return nil, err return nil, err
} }
raw := hub.conn
if streamSettings.UdpmaskManager != nil {
hub.conn, err = streamSettings.UdpmaskManager.WrapPacketConnServer(raw)
if err != nil {
raw.Close()
return nil, errors.New("mask err").Base(err)
}
}
errors.LogInfo(ctx, "listening UDP on ", address, ":", port) errors.LogInfo(ctx, "listening UDP on ", address, ":", port)
hub.conn = udpConn.(*net.UDPConn) hub.udpConn, _ = hub.conn.(*net.UDPConn)
hub.cache = make(chan *udp.Packet, hub.capacity) hub.cache = make(chan *udp.Packet, hub.capacity)
go hub.start() go hub.start()
@@ -78,7 +91,7 @@ func (h *Hub) Close() error {
} }
func (h *Hub) WriteTo(payload []byte, dest net.Destination) (int, error) { func (h *Hub) WriteTo(payload []byte, dest net.Destination) (int, error) {
return h.conn.WriteToUDP(payload, &net.UDPAddr{ return h.conn.WriteTo(payload, &net.UDPAddr{
IP: dest.Address.IP(), IP: dest.Address.IP(),
Port: int(dest.Port), Port: int(dest.Port),
}) })
@@ -93,10 +106,21 @@ func (h *Hub) start() {
for { for {
buffer := buf.New() buffer := buf.New()
var noob int var noob int
var addr *net.UDPAddr var udpAddr *net.UDPAddr
rawBytes := buffer.Extend(buf.Size) rawBytes := buffer.Extend(buf.Size)
n, noob, _, addr, err := ReadUDPMsg(h.conn, rawBytes, oobBytes) var n int
var err error
if h.udpConn != nil {
n, noob, _, udpAddr, err = ReadUDPMsg(h.udpConn, rawBytes, oobBytes)
} else {
var addr net.Addr
n, addr, err = h.conn.ReadFrom(rawBytes)
if err == nil {
udpAddr = addr.(*net.UDPAddr)
}
}
if err != nil { if err != nil {
errors.LogInfoInner(context.Background(), err, "failed to read UDP msg") errors.LogInfoInner(context.Background(), err, "failed to read UDP msg")
buffer.Release() buffer.Release()
@@ -111,7 +135,7 @@ func (h *Hub) start() {
payload := &udp.Packet{ payload := &udp.Packet{
Payload: buffer, Payload: buffer,
Source: net.UDPDestination(net.IPAddress(addr.IP), net.Port(addr.Port)), Source: net.UDPDestination(net.IPAddress(udpAddr.IP), net.Port(udpAddr.Port)),
} }
if h.recvOrigDest && noob > 0 { if h.recvOrigDest && noob > 0 {
payload.Target = RetrieveOriginalDest(oobBytes[:noob]) payload.Target = RetrieveOriginalDest(oobBytes[:noob])