mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-05-08 14:13:22 +00:00
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:
@@ -4,72 +4,17 @@ import (
|
||||
"sort"
|
||||
|
||||
"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/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"
|
||||
)
|
||||
|
||||
type NoOpAuthenticator struct{}
|
||||
|
||||
func (NoOpAuthenticator) Build() (proto.Message, error) {
|
||||
return new(noop.Config), nil
|
||||
}
|
||||
|
||||
type NoOpConnectionAuthenticator struct{}
|
||||
|
||||
func (NoOpConnectionAuthenticator) Build() (proto.Message, error) {
|
||||
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 {
|
||||
Version string `json:"version"`
|
||||
Method string `json:"method"`
|
||||
|
||||
@@ -16,7 +16,16 @@ import (
|
||||
"github.com/xtls/xray-core/common/platform/filesystem"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"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/xdns"
|
||||
"github.com/xtls/xray-core/transport/internet/httpupgrade"
|
||||
"github.com/xtls/xray-core/transport/internet/hysteria"
|
||||
"github.com/xtls/xray-core/transport/internet/kcp"
|
||||
@@ -29,16 +38,6 @@ import (
|
||||
)
|
||||
|
||||
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{
|
||||
"none": func() interface{} { return new(NoOpConnectionAuthenticator) },
|
||||
"http": func() interface{} { return new(Authenticator) },
|
||||
@@ -63,9 +62,9 @@ func (c *KCPConfig) Build() (proto.Message, error) {
|
||||
|
||||
if c.Mtu != nil {
|
||||
mtu := *c.Mtu
|
||||
if mtu < 576 || mtu > 1460 {
|
||||
return nil, errors.New("invalid mKCP MTU size: ", mtu).AtError()
|
||||
}
|
||||
// if mtu < 576 || mtu > 1460 {
|
||||
// return nil, errors.New("invalid mKCP MTU size: ", mtu).AtError()
|
||||
// }
|
||||
config.Mtu = &kcp.MTU{Value: mtu}
|
||||
}
|
||||
if c.Tti != nil {
|
||||
@@ -100,20 +99,8 @@ func (c *KCPConfig) Build() (proto.Message, error) {
|
||||
config.WriteBuffer = &kcp.WriteBuffer{Size: 512 * 1024}
|
||||
}
|
||||
}
|
||||
if len(c.HeaderConfig) > 0 {
|
||||
headerConfig, _, err := kcpHeaderLoader.Load(c.HeaderConfig)
|
||||
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}
|
||||
if c.HeaderConfig != nil || c.Seed != nil {
|
||||
return nil, errors.PrintRemovedFeatureError("mkcp header & seed", "finalmask/udp header-* & mkcp-original & mkcp-aes128gcm")
|
||||
}
|
||||
|
||||
return config, nil
|
||||
@@ -1242,10 +1229,80 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
|
||||
|
||||
var (
|
||||
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 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 {
|
||||
Password string `json:"password"`
|
||||
}
|
||||
@@ -1256,14 +1313,28 @@ func (c *Salamander) Build() (proto.Message, error) {
|
||||
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"`
|
||||
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
|
||||
if tcpmaskLoader {
|
||||
if tcp {
|
||||
return nil, errors.New("")
|
||||
}
|
||||
|
||||
@@ -1282,12 +1353,17 @@ func (c *FinalMask) Build(tcpmaskLoader bool) (proto.Message, error) {
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
type FinalMask struct {
|
||||
Tcp []Mask `json:"tcp"`
|
||||
Udp []Mask `json:"udp"`
|
||||
}
|
||||
|
||||
type StreamConfig struct {
|
||||
Address *Address `json:"address"`
|
||||
Port uint16 `json:"port"`
|
||||
Network *TransportProtocol `json:"network"`
|
||||
Security string `json:"security"`
|
||||
Udpmasks []*FinalMask `json:"udpmasks"`
|
||||
FinalMask *FinalMask `json:"finalmask"`
|
||||
TLSSettings *TLSConfig `json:"tlsSettings"`
|
||||
REALITYSettings *REALITYConfig `json:"realitySettings"`
|
||||
RAWSettings *TCPConfig `json:"rawSettings"`
|
||||
@@ -1437,12 +1513,21 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
|
||||
config.SocketSettings = ss
|
||||
}
|
||||
|
||||
for _, mask := range c.Udpmasks {
|
||||
u, err := mask.Build(false)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build mask with type ", mask.Type).Base(err)
|
||||
if c.FinalMask != nil {
|
||||
for _, mask := range c.FinalMask.Tcp {
|
||||
u, err := mask.Build(true)
|
||||
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
|
||||
|
||||
@@ -63,11 +63,6 @@ import (
|
||||
// Transport headers
|
||||
_ "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/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
|
||||
_ "github.com/xtls/xray-core/main/json"
|
||||
|
||||
@@ -4,17 +4,15 @@ import (
|
||||
"net"
|
||||
)
|
||||
|
||||
type ConnSize interface {
|
||||
Size() int32
|
||||
}
|
||||
|
||||
type Udpmask interface {
|
||||
UDP()
|
||||
|
||||
WrapConnClient(net.Conn) (net.Conn, error)
|
||||
WrapConnServer(net.Conn) (net.Conn, error)
|
||||
|
||||
WrapPacketConnClient(net.PacketConn) (net.PacketConn, error)
|
||||
WrapPacketConnServer(net.PacketConn) (net.PacketConn, error)
|
||||
|
||||
Size() int
|
||||
Serialize([]byte)
|
||||
WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error)
|
||||
WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error)
|
||||
}
|
||||
|
||||
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) {
|
||||
leaveSize := int32(0)
|
||||
var err error
|
||||
for _, mask := range m.udpmasks {
|
||||
raw, err = mask.WrapPacketConnClient(raw)
|
||||
for i, mask := range m.udpmasks {
|
||||
raw, err = mask.WrapPacketConnClient(raw, i == len(m.udpmasks)-1, leaveSize, i == 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
leaveSize += raw.(ConnSize).Size()
|
||||
}
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
func (m *UdpmaskManager) WrapPacketConnServer(raw net.PacketConn) (net.PacketConn, error) {
|
||||
leaveSize := int32(0)
|
||||
var err error
|
||||
for _, mask := range m.udpmasks {
|
||||
raw, err = mask.WrapPacketConnServer(raw)
|
||||
for i, mask := range m.udpmasks {
|
||||
raw, err = mask.WrapPacketConnServer(raw, i == len(m.udpmasks)-1, leaveSize, i == 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
leaveSize += raw.(ConnSize).Size()
|
||||
}
|
||||
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 {
|
||||
TCP()
|
||||
|
||||
|
||||
16
transport/internet/finalmask/header/dns/config.go
Normal file
16
transport/internet/finalmask/header/dns/config.go
Normal file
@@ -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)
|
||||
}
|
||||
123
transport/internet/finalmask/header/dns/config.pb.go
Normal file
123
transport/internet/finalmask/header/dns/config.pb.go
Normal file
@@ -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
|
||||
}
|
||||
11
transport/internet/finalmask/header/dns/config.proto
Normal file
11
transport/internet/finalmask/header/dns/config.proto
Normal file
@@ -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;
|
||||
}
|
||||
241
transport/internet/finalmask/header/dns/conn.go
Normal file
241
transport/internet/finalmask/header/dns/conn.go
Normal file
@@ -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)
|
||||
}
|
||||
16
transport/internet/finalmask/header/dtls/config.go
Normal file
16
transport/internet/finalmask/header/dtls/config.go
Normal file
@@ -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)
|
||||
}
|
||||
114
transport/internet/finalmask/header/dtls/config.pb.go
Normal file
114
transport/internet/finalmask/header/dtls/config.pb.go
Normal file
@@ -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
|
||||
}
|
||||
9
transport/internet/finalmask/header/dtls/config.proto
Normal file
9
transport/internet/finalmask/header/dtls/config.proto
Normal file
@@ -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 {}
|
||||
178
transport/internet/finalmask/header/dtls/conn.go
Normal file
178
transport/internet/finalmask/header/dtls/conn.go
Normal file
@@ -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)
|
||||
}
|
||||
16
transport/internet/finalmask/header/srtp/config.go
Normal file
16
transport/internet/finalmask/header/srtp/config.go
Normal file
@@ -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)
|
||||
}
|
||||
114
transport/internet/finalmask/header/srtp/config.pb.go
Normal file
114
transport/internet/finalmask/header/srtp/config.pb.go
Normal file
@@ -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
|
||||
}
|
||||
9
transport/internet/finalmask/header/srtp/config.proto
Normal file
9
transport/internet/finalmask/header/srtp/config.proto
Normal file
@@ -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 {}
|
||||
162
transport/internet/finalmask/header/srtp/conn.go
Normal file
162
transport/internet/finalmask/header/srtp/conn.go
Normal file
@@ -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)
|
||||
}
|
||||
16
transport/internet/finalmask/header/utp/config.go
Normal file
16
transport/internet/finalmask/header/utp/config.go
Normal file
@@ -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)
|
||||
}
|
||||
114
transport/internet/finalmask/header/utp/config.pb.go
Normal file
114
transport/internet/finalmask/header/utp/config.pb.go
Normal file
@@ -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
|
||||
}
|
||||
9
transport/internet/finalmask/header/utp/config.proto
Normal file
9
transport/internet/finalmask/header/utp/config.proto
Normal file
@@ -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 {}
|
||||
164
transport/internet/finalmask/header/utp/conn.go
Normal file
164
transport/internet/finalmask/header/utp/conn.go
Normal file
@@ -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)
|
||||
}
|
||||
16
transport/internet/finalmask/header/wechat/config.go
Normal file
16
transport/internet/finalmask/header/wechat/config.go
Normal file
@@ -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)
|
||||
}
|
||||
114
transport/internet/finalmask/header/wechat/config.pb.go
Normal file
114
transport/internet/finalmask/header/wechat/config.pb.go
Normal file
@@ -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
|
||||
}
|
||||
9
transport/internet/finalmask/header/wechat/config.proto
Normal file
9
transport/internet/finalmask/header/wechat/config.proto
Normal file
@@ -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 {}
|
||||
168
transport/internet/finalmask/header/wechat/conn.go
Normal file
168
transport/internet/finalmask/header/wechat/conn.go
Normal file
@@ -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)
|
||||
}
|
||||
16
transport/internet/finalmask/header/wireguard/config.go
Normal file
16
transport/internet/finalmask/header/wireguard/config.go
Normal file
@@ -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)
|
||||
}
|
||||
114
transport/internet/finalmask/header/wireguard/config.pb.go
Normal file
114
transport/internet/finalmask/header/wireguard/config.pb.go
Normal file
@@ -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 {}
|
||||
155
transport/internet/finalmask/header/wireguard/conn.go
Normal file
155
transport/internet/finalmask/header/wireguard/conn.go
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
16
transport/internet/finalmask/mkcp/aes128gcm/config.go
Normal file
16
transport/internet/finalmask/mkcp/aes128gcm/config.go
Normal file
@@ -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)
|
||||
}
|
||||
123
transport/internet/finalmask/mkcp/aes128gcm/config.pb.go
Normal file
123
transport/internet/finalmask/mkcp/aes128gcm/config.pb.go
Normal file
@@ -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
|
||||
}
|
||||
11
transport/internet/finalmask/mkcp/aes128gcm/config.proto
Normal file
11
transport/internet/finalmask/mkcp/aes128gcm/config.proto
Normal file
@@ -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;
|
||||
}
|
||||
174
transport/internet/finalmask/mkcp/aes128gcm/conn.go
Normal file
174
transport/internet/finalmask/mkcp/aes128gcm/conn.go
Normal file
@@ -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)
|
||||
}
|
||||
16
transport/internet/finalmask/mkcp/original/config.go
Normal file
16
transport/internet/finalmask/mkcp/original/config.go
Normal file
@@ -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)
|
||||
}
|
||||
114
transport/internet/finalmask/mkcp/original/config.pb.go
Normal file
114
transport/internet/finalmask/mkcp/original/config.pb.go
Normal file
@@ -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
|
||||
}
|
||||
9
transport/internet/finalmask/mkcp/original/config.proto
Normal file
9
transport/internet/finalmask/mkcp/original/config.proto
Normal file
@@ -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 {}
|
||||
225
transport/internet/finalmask/mkcp/original/conn.go
Normal file
225
transport/internet/finalmask/mkcp/original/conn.go
Normal file
@@ -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)
|
||||
}
|
||||
19
transport/internet/finalmask/mkcp/original/simple_test.go
Normal file
19
transport/internet/finalmask/mkcp/original/simple_test.go
Normal file
@@ -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
|
||||
// +build !amd64
|
||||
|
||||
package kcp
|
||||
package original
|
||||
|
||||
// xorfwd performs XOR forwards in words, x[i] ^= x[i-4], i from 0 to len
|
||||
func xorfwd(x []byte) {
|
||||
@@ -1,4 +1,4 @@
|
||||
package kcp
|
||||
package original
|
||||
|
||||
//go:noescape
|
||||
func xorfwd(x []byte)
|
||||
@@ -2,41 +2,15 @@ package salamander
|
||||
|
||||
import (
|
||||
"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) WrapConnClient(raw net.Conn) (net.Conn, error) {
|
||||
return raw, nil
|
||||
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) WrapConnServer(raw net.Conn) (net.Conn, error) {
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
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) {
|
||||
func (c *Config) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
|
||||
return NewConnServer(c, raw, first, leaveSize)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.10
|
||||
// protoc v6.33.1
|
||||
// source: transport/internet/udpmask/salamander/config.proto
|
||||
// source: transport/internet/finalmask/salamander/config.proto
|
||||
|
||||
package salamander
|
||||
|
||||
@@ -30,7 +30,7 @@ type Config struct {
|
||||
|
||||
func (x *Config) Reset() {
|
||||
*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.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -42,7 +42,7 @@ func (x *Config) String() string {
|
||||
func (*Config) ProtoMessage() {}
|
||||
|
||||
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 {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -55,7 +55,7 @@ func (x *Config) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||
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 {
|
||||
@@ -65,32 +65,32 @@ func (x *Config) GetPassword() string {
|
||||
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" +
|
||||
"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" +
|
||||
"\bpassword\x18\x01 \x01(\tR\bpasswordB\xa0\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"
|
||||
"\bpassword\x18\x01 \x01(\tR\bpasswordB\xa6\x01\n" +
|
||||
"0com.xray.transport.internet.finalmask.salamanderP\x01ZAgithub.com/xtls/xray-core/transport/internet/finalmask/salamander\xaa\x02,Xray.Transport.Internet.Finalmask.Salamanderb\x06proto3"
|
||||
|
||||
var (
|
||||
file_transport_internet_udpmask_salamander_config_proto_rawDescOnce sync.Once
|
||||
file_transport_internet_udpmask_salamander_config_proto_rawDescData []byte
|
||||
file_transport_internet_finalmask_salamander_config_proto_rawDescOnce sync.Once
|
||||
file_transport_internet_finalmask_salamander_config_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_transport_internet_udpmask_salamander_config_proto_rawDescGZIP() []byte {
|
||||
file_transport_internet_udpmask_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)))
|
||||
func file_transport_internet_finalmask_salamander_config_proto_rawDescGZIP() []byte {
|
||||
file_transport_internet_finalmask_salamander_config_proto_rawDescOnce.Do(func() {
|
||||
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_udpmask_salamander_config_proto_goTypes = []any{
|
||||
(*Config)(nil), // 0: xray.transport.internet.udpmask.salamander.Config
|
||||
var file_transport_internet_finalmask_salamander_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_transport_internet_finalmask_salamander_config_proto_goTypes = []any{
|
||||
(*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 input_type
|
||||
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
|
||||
}
|
||||
|
||||
func init() { file_transport_internet_udpmask_salamander_config_proto_init() }
|
||||
func file_transport_internet_udpmask_salamander_config_proto_init() {
|
||||
if File_transport_internet_udpmask_salamander_config_proto != nil {
|
||||
func init() { file_transport_internet_finalmask_salamander_config_proto_init() }
|
||||
func file_transport_internet_finalmask_salamander_config_proto_init() {
|
||||
if File_transport_internet_finalmask_salamander_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_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,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_transport_internet_udpmask_salamander_config_proto_goTypes,
|
||||
DependencyIndexes: file_transport_internet_udpmask_salamander_config_proto_depIdxs,
|
||||
MessageInfos: file_transport_internet_udpmask_salamander_config_proto_msgTypes,
|
||||
GoTypes: file_transport_internet_finalmask_salamander_config_proto_goTypes,
|
||||
DependencyIndexes: file_transport_internet_finalmask_salamander_config_proto_depIdxs,
|
||||
MessageInfos: file_transport_internet_finalmask_salamander_config_proto_msgTypes,
|
||||
}.Build()
|
||||
File_transport_internet_udpmask_salamander_config_proto = out.File
|
||||
file_transport_internet_udpmask_salamander_config_proto_goTypes = nil
|
||||
file_transport_internet_udpmask_salamander_config_proto_depIdxs = nil
|
||||
File_transport_internet_finalmask_salamander_config_proto = out.File
|
||||
file_transport_internet_finalmask_salamander_config_proto_goTypes = nil
|
||||
file_transport_internet_finalmask_salamander_config_proto_depIdxs = nil
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package xray.transport.internet.udpmask.salamander;
|
||||
option csharp_namespace = "Xray.Transport.Internet.Udpmask.Salamander";
|
||||
option go_package = "github.com/xtls/xray-core/transport/internet/udpmask/salamander";
|
||||
option java_package = "com.xray.transport.internet.udpmask.salamander";
|
||||
package xray.transport.internet.finalmask.salamander;
|
||||
option csharp_namespace = "Xray.Transport.Internet.Finalmask.Salamander";
|
||||
option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/salamander";
|
||||
option java_package = "com.xray.transport.internet.finalmask.salamander";
|
||||
option java_multiple_files = true;
|
||||
|
||||
message Config {
|
||||
|
||||
147
transport/internet/finalmask/salamander/conn.go
Normal file
147
transport/internet/finalmask/salamander/conn.go
Normal file
@@ -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 (
|
||||
"fmt"
|
||||
@@ -15,8 +15,6 @@ const (
|
||||
smKeyLen = blake2b.Size256
|
||||
)
|
||||
|
||||
var _ Obfuscator = (*SalamanderObfuscator)(nil)
|
||||
|
||||
var ErrPSKTooShort = fmt.Errorf("PSK must be at least %d bytes", smPSKMinLen)
|
||||
|
||||
// SalamanderObfuscator is an obfuscator that obfuscates each packet with
|
||||
81
transport/internet/finalmask/salamander/salamander_test.go
Normal file
81
transport/internet/finalmask/salamander/salamander_test.go
Normal file
@@ -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
transport/internet/finalmask/udp_test.go
Normal file
129
transport/internet/finalmask/udp_test.go
Normal 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
transport/internet/finalmask/xdns/client.go
Normal file
373
transport/internet/finalmask/xdns/client.go
Normal 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
|
||||
}
|
||||
16
transport/internet/finalmask/xdns/config.go
Normal file
16
transport/internet/finalmask/xdns/config.go
Normal file
@@ -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)
|
||||
}
|
||||
123
transport/internet/finalmask/xdns/config.pb.go
Normal file
123
transport/internet/finalmask/xdns/config.pb.go
Normal file
@@ -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
|
||||
}
|
||||
12
transport/internet/finalmask/xdns/config.proto
Normal file
12
transport/internet/finalmask/xdns/config.proto
Normal file
@@ -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
transport/internet/finalmask/xdns/dns.go
Normal file
575
transport/internet/finalmask/xdns/dns.go
Normal 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()
|
||||
}
|
||||
592
transport/internet/finalmask/xdns/dns_test.go
Normal file
592
transport/internet/finalmask/xdns/dns_test.go
Normal file
@@ -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
transport/internet/finalmask/xdns/server.go
Normal file
567
transport/internet/finalmask/xdns/server.go
Normal 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
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
@@ -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 {}
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
@@ -176,6 +176,7 @@ func (c *client) dial() error {
|
||||
}
|
||||
pktConn, err = udphop.NewUDPHopPacketConn(addr, c.config.IntervalMin, c.config.IntervalMax, c.udphopDialer, pktConn, index)
|
||||
if err != nil {
|
||||
raw.Close()
|
||||
return errors.New("udphop err").Base(err)
|
||||
}
|
||||
}
|
||||
@@ -183,6 +184,7 @@ func (c *client) dial() error {
|
||||
if c.udpmaskManager != nil {
|
||||
pktConn, err = c.udpmaskManager.WrapPacketConnClient(pktConn)
|
||||
if err != nil {
|
||||
raw.Close()
|
||||
return errors.New("mask err").Base(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package kcp
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
)
|
||||
@@ -48,32 +46,12 @@ func (c *Config) GetWriteBufferSize() uint32 {
|
||||
}
|
||||
|
||||
// GetReadBufferSize returns the size of ReadBuffer in bytes.
|
||||
func (c *Config) GetReadBufferSize() uint32 {
|
||||
if c == nil || c.ReadBuffer == nil {
|
||||
return 2 * 1024 * 1024
|
||||
}
|
||||
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) GetReadBufferSize() uint32 {
|
||||
// if c == nil || c.ReadBuffer == nil {
|
||||
// return 2 * 1024 * 1024
|
||||
// }
|
||||
// return c.ReadBuffer.Size
|
||||
// }
|
||||
|
||||
func (c *Config) GetSendingInFlightSize() uint32 {
|
||||
size := c.GetUplinkCapacityValue() * 1024 * 1024 / c.GetMTUValue() / (1000 / c.GetTTIValue())
|
||||
@@ -95,9 +73,9 @@ func (c *Config) GetReceivingInFlightSize() uint32 {
|
||||
return size
|
||||
}
|
||||
|
||||
func (c *Config) GetReceivingBufferSize() uint32 {
|
||||
return c.GetReadBufferSize() / c.GetMTUValue()
|
||||
}
|
||||
// func (c *Config) GetReceivingBufferSize() uint32 {
|
||||
// return c.GetReadBufferSize() / c.GetMTUValue()
|
||||
// }
|
||||
|
||||
func init() {
|
||||
common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {
|
||||
|
||||
@@ -204,7 +204,7 @@ type Connection struct {
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
conn := &Connection{
|
||||
@@ -215,7 +215,7 @@ func NewConnection(meta ConnMetadata, writer PacketWriter, closer io.Closer, con
|
||||
dataOutput: signal.NewNotifier(),
|
||||
Config: config,
|
||||
output: NewRetryableWriter(NewSegmentWriter(writer)),
|
||||
mss: config.GetMTUValue() - uint32(writer.Overhead()) - DataSegmentOverhead,
|
||||
mss: config.GetMTUValue() - DataSegmentOverhead,
|
||||
roundTrip: &RoundTripInfo{
|
||||
rto: 100,
|
||||
minRtt: config.GetTTIValue(),
|
||||
|
||||
@@ -16,9 +16,7 @@ func (NoOpCloser) Close() error {
|
||||
}
|
||||
|
||||
func TestConnectionReadTimeout(t *testing.T) {
|
||||
conn := NewConnection(ConnMetadata{Conversation: 1}, &KCPPacketWriter{
|
||||
Writer: buf.DiscardBytes,
|
||||
}, NoOpCloser(0), &Config{})
|
||||
conn := NewConnection(ConnMetadata{Conversation: 1}, buf.DiscardBytes, NoOpCloser(0), &Config{})
|
||||
conn.SetReadDeadline(time.Now().Add(time.Second))
|
||||
|
||||
b := make([]byte, 1024)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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])
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
header, err := kcpSettings.GetPackerHeader()
|
||||
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,
|
||||
}
|
||||
reader := &KCPPacketReader{}
|
||||
|
||||
conv := uint16(atomic.AddUint32(&globalConv, 1))
|
||||
session := NewConnection(ConnMetadata{
|
||||
LocalAddr: rawConn.LocalAddr(),
|
||||
RemoteAddr: rawConn.RemoteAddr(),
|
||||
Conversation: conv,
|
||||
}, writer, rawConn, kcpSettings)
|
||||
}, rawConn, rawConn, kcpSettings)
|
||||
|
||||
go fetchInput(ctx, rawConn, reader, session)
|
||||
|
||||
|
||||
@@ -1,48 +1,12 @@
|
||||
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 {
|
||||
Read([]byte) []Segment
|
||||
}
|
||||
|
||||
type PacketWriter interface {
|
||||
Overhead() int
|
||||
io.Writer
|
||||
}
|
||||
|
||||
type KCPPacketReader struct {
|
||||
Security cipher.AEAD
|
||||
Header internet.PacketHeader
|
||||
}
|
||||
type KCPPacketReader struct{}
|
||||
|
||||
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
|
||||
for len(b) > 0 {
|
||||
seg, x := ReadSegment(b)
|
||||
@@ -54,42 +18,3 @@ func (r *KCPPacketReader) Read(b []byte) []Segment {
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@ import (
|
||||
)
|
||||
|
||||
func TestKCPPacketReader(t *testing.T) {
|
||||
reader := KCPPacketReader{
|
||||
Security: &SimpleAuthenticator{},
|
||||
}
|
||||
reader := KCPPacketReader{}
|
||||
|
||||
testCases := []struct {
|
||||
Input []byte
|
||||
|
||||
@@ -2,7 +2,6 @@ package kcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/cipher"
|
||||
gotls "crypto/tls"
|
||||
"sync"
|
||||
|
||||
@@ -30,28 +29,14 @@ type Listener struct {
|
||||
tlsConfig *gotls.Config
|
||||
config *Config
|
||||
reader PacketReader
|
||||
header internet.PacketHeader
|
||||
security cipher.AEAD
|
||||
addConn internet.ConnHandler
|
||||
}
|
||||
|
||||
func NewListener(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, addConn internet.ConnHandler) (*Listener, error) {
|
||||
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{
|
||||
header: header,
|
||||
security: security,
|
||||
reader: &KCPPacketReader{
|
||||
Header: header,
|
||||
Security: security,
|
||||
},
|
||||
reader: &KCPPacketReader{},
|
||||
sessions: make(map[ConnectionID]*Connection),
|
||||
config: kcpSettings,
|
||||
addConn: addConn,
|
||||
@@ -124,11 +109,7 @@ func (l *Listener) OnReceive(payload *buf.Buffer, src net.Destination) {
|
||||
LocalAddr: localAddr,
|
||||
RemoteAddr: remoteAddr,
|
||||
Conversation: conv,
|
||||
}, &KCPPacketWriter{
|
||||
Header: l.header,
|
||||
Security: l.security,
|
||||
Writer: writer,
|
||||
}, writer, l.config)
|
||||
}, writer, writer, l.config)
|
||||
var netConn stat.Connection = conn
|
||||
if l.tlsConfig != nil {
|
||||
netConn = tls.Server(conn, l.tlsConfig)
|
||||
|
||||
@@ -25,7 +25,8 @@ func HubReceiveOriginalDestination(r bool) HubOption {
|
||||
}
|
||||
|
||||
type Hub struct {
|
||||
conn *net.UDPConn
|
||||
conn net.PacketConn
|
||||
udpConn *net.UDPConn
|
||||
cache chan *udp.Packet
|
||||
capacity int
|
||||
recvOrigDest bool
|
||||
@@ -56,15 +57,27 @@ func ListenUDP(ctx context.Context, address net.Address, port net.Port, streamSe
|
||||
hub.recvOrigDest = true
|
||||
}
|
||||
|
||||
udpConn, err := internet.ListenSystemPacket(ctx, &net.UDPAddr{
|
||||
var err error
|
||||
hub.conn, err = internet.ListenSystemPacket(ctx, &net.UDPAddr{
|
||||
IP: address.IP(),
|
||||
Port: int(port),
|
||||
}, sockopt)
|
||||
if err != nil {
|
||||
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)
|
||||
hub.conn = udpConn.(*net.UDPConn)
|
||||
hub.udpConn, _ = hub.conn.(*net.UDPConn)
|
||||
hub.cache = make(chan *udp.Packet, hub.capacity)
|
||||
|
||||
go hub.start()
|
||||
@@ -78,7 +91,7 @@ func (h *Hub) Close() 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(),
|
||||
Port: int(dest.Port),
|
||||
})
|
||||
@@ -93,10 +106,21 @@ func (h *Hub) start() {
|
||||
for {
|
||||
buffer := buf.New()
|
||||
var noob int
|
||||
var addr *net.UDPAddr
|
||||
var udpAddr *net.UDPAddr
|
||||
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 {
|
||||
errors.LogInfoInner(context.Background(), err, "failed to read UDP msg")
|
||||
buffer.Release()
|
||||
@@ -111,7 +135,7 @@ func (h *Hub) start() {
|
||||
|
||||
payload := &udp.Packet{
|
||||
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 {
|
||||
payload.Target = RetrieveOriginalDest(oobBytes[:noob])
|
||||
|
||||
Reference in New Issue
Block a user