This commit is contained in:
RPRX 2020-11-25 19:01:53 +08:00
parent 47d23e9972
commit c7f7c08ead
711 changed files with 82154 additions and 2 deletions

211
common/net/address.go Normal file
View file

@ -0,0 +1,211 @@
package net
import (
"bytes"
"net"
"strings"
)
var (
// LocalHostIP is a constant value for localhost IP in IPv4.
LocalHostIP = IPAddress([]byte{127, 0, 0, 1})
// AnyIP is a constant value for any IP in IPv4.
AnyIP = IPAddress([]byte{0, 0, 0, 0})
// LocalHostDomain is a constant value for localhost domain.
LocalHostDomain = DomainAddress("localhost")
// LocalHostIPv6 is a constant value for localhost IP in IPv6.
LocalHostIPv6 = IPAddress([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1})
// AnyIPv6 is a constant value for any IP in IPv6.
AnyIPv6 = IPAddress([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
)
// AddressFamily is the type of address.
type AddressFamily byte
const (
// AddressFamilyIPv4 represents address as IPv4
AddressFamilyIPv4 = AddressFamily(0)
// AddressFamilyIPv6 represents address as IPv6
AddressFamilyIPv6 = AddressFamily(1)
// AddressFamilyDomain represents address as Domain
AddressFamilyDomain = AddressFamily(2)
)
// IsIPv4 returns true if current AddressFamily is IPv4.
func (af AddressFamily) IsIPv4() bool {
return af == AddressFamilyIPv4
}
// IsIPv6 returns true if current AddressFamily is IPv6.
func (af AddressFamily) IsIPv6() bool {
return af == AddressFamilyIPv6
}
// IsIP returns true if current AddressFamily is IPv6 or IPv4.
func (af AddressFamily) IsIP() bool {
return af == AddressFamilyIPv4 || af == AddressFamilyIPv6
}
// IsDomain returns true if current AddressFamily is Domain.
func (af AddressFamily) IsDomain() bool {
return af == AddressFamilyDomain
}
// Address represents a network address to be communicated with. It may be an IP address or domain
// address, not both. This interface doesn't resolve IP address for a given domain.
type Address interface {
IP() net.IP // IP of this Address
Domain() string // Domain of this Address
Family() AddressFamily
String() string // String representation of this Address
}
func isAlphaNum(c byte) bool {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
}
// ParseAddress parses a string into an Address. The return value will be an IPAddress when
// the string is in the form of IPv4 or IPv6 address, or a DomainAddress otherwise.
func ParseAddress(addr string) Address {
// Handle IPv6 address in form as "[2001:4860:0:2001::68]"
lenAddr := len(addr)
if lenAddr > 0 && addr[0] == '[' && addr[lenAddr-1] == ']' {
addr = addr[1 : lenAddr-1]
lenAddr -= 2
}
if lenAddr > 0 && (!isAlphaNum(addr[0]) || !isAlphaNum(addr[len(addr)-1])) {
addr = strings.TrimSpace(addr)
}
ip := net.ParseIP(addr)
if ip != nil {
return IPAddress(ip)
}
return DomainAddress(addr)
}
var bytes0 = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
// IPAddress creates an Address with given IP.
func IPAddress(ip []byte) Address {
switch len(ip) {
case net.IPv4len:
var addr ipv4Address = [4]byte{ip[0], ip[1], ip[2], ip[3]}
return addr
case net.IPv6len:
if bytes.Equal(ip[:10], bytes0) && ip[10] == 0xff && ip[11] == 0xff {
return IPAddress(ip[12:16])
}
var addr ipv6Address = [16]byte{
ip[0], ip[1], ip[2], ip[3],
ip[4], ip[5], ip[6], ip[7],
ip[8], ip[9], ip[10], ip[11],
ip[12], ip[13], ip[14], ip[15],
}
return addr
default:
newError("invalid IP format: ", ip).AtError().WriteToLog()
return nil
}
}
// DomainAddress creates an Address with given domain.
func DomainAddress(domain string) Address {
return domainAddress(domain)
}
type ipv4Address [4]byte
func (a ipv4Address) IP() net.IP {
return net.IP(a[:])
}
func (ipv4Address) Domain() string {
panic("Calling Domain() on an IPv4Address.")
}
func (ipv4Address) Family() AddressFamily {
return AddressFamilyIPv4
}
func (a ipv4Address) String() string {
return a.IP().String()
}
type ipv6Address [16]byte
func (a ipv6Address) IP() net.IP {
return net.IP(a[:])
}
func (ipv6Address) Domain() string {
panic("Calling Domain() on an IPv6Address.")
}
func (ipv6Address) Family() AddressFamily {
return AddressFamilyIPv6
}
func (a ipv6Address) String() string {
return "[" + a.IP().String() + "]"
}
type domainAddress string
func (domainAddress) IP() net.IP {
panic("Calling IP() on a DomainAddress.")
}
func (a domainAddress) Domain() string {
return string(a)
}
func (domainAddress) Family() AddressFamily {
return AddressFamilyDomain
}
func (a domainAddress) String() string {
return a.Domain()
}
// AsAddress translates IPOrDomain to Address.
func (d *IPOrDomain) AsAddress() Address {
if d == nil {
return nil
}
switch addr := d.Address.(type) {
case *IPOrDomain_Ip:
return IPAddress(addr.Ip)
case *IPOrDomain_Domain:
return DomainAddress(addr.Domain)
}
panic("Common|Net: Invalid address.")
}
// NewIPOrDomain translates Address to IPOrDomain
func NewIPOrDomain(addr Address) *IPOrDomain {
switch addr.Family() {
case AddressFamilyDomain:
return &IPOrDomain{
Address: &IPOrDomain_Domain{
Domain: addr.Domain(),
},
}
case AddressFamilyIPv4, AddressFamilyIPv6:
return &IPOrDomain{
Address: &IPOrDomain_Ip{
Ip: addr.IP(),
},
}
default:
panic("Unknown Address type.")
}
}

195
common/net/address.pb.go Normal file
View file

@ -0,0 +1,195 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.14.0
// source: common/net/address.proto
package net
import (
proto "github.com/golang/protobuf/proto"
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)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// Address of a network host. It may be either an IP address or a domain
// address.
type IPOrDomain struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Types that are assignable to Address:
// *IPOrDomain_Ip
// *IPOrDomain_Domain
Address isIPOrDomain_Address `protobuf_oneof:"address"`
}
func (x *IPOrDomain) Reset() {
*x = IPOrDomain{}
if protoimpl.UnsafeEnabled {
mi := &file_common_net_address_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *IPOrDomain) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*IPOrDomain) ProtoMessage() {}
func (x *IPOrDomain) ProtoReflect() protoreflect.Message {
mi := &file_common_net_address_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use IPOrDomain.ProtoReflect.Descriptor instead.
func (*IPOrDomain) Descriptor() ([]byte, []int) {
return file_common_net_address_proto_rawDescGZIP(), []int{0}
}
func (m *IPOrDomain) GetAddress() isIPOrDomain_Address {
if m != nil {
return m.Address
}
return nil
}
func (x *IPOrDomain) GetIp() []byte {
if x, ok := x.GetAddress().(*IPOrDomain_Ip); ok {
return x.Ip
}
return nil
}
func (x *IPOrDomain) GetDomain() string {
if x, ok := x.GetAddress().(*IPOrDomain_Domain); ok {
return x.Domain
}
return ""
}
type isIPOrDomain_Address interface {
isIPOrDomain_Address()
}
type IPOrDomain_Ip struct {
// IP address. Must by either 4 or 16 bytes.
Ip []byte `protobuf:"bytes,1,opt,name=ip,proto3,oneof"`
}
type IPOrDomain_Domain struct {
// Domain address.
Domain string `protobuf:"bytes,2,opt,name=domain,proto3,oneof"`
}
func (*IPOrDomain_Ip) isIPOrDomain_Address() {}
func (*IPOrDomain_Domain) isIPOrDomain_Address() {}
var File_common_net_address_proto protoreflect.FileDescriptor
var file_common_net_address_proto_rawDesc = []byte{
0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x61, 0x64, 0x64,
0x72, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x22, 0x43, 0x0a, 0x0a, 0x49,
0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x10, 0x0a, 0x02, 0x69, 0x70, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x02, 0x69, 0x70, 0x12, 0x18, 0x0a, 0x06, 0x64,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x64,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x42, 0x09, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
0x42, 0x52, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x27, 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, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e,
0x65, 0x74, 0xaa, 0x02, 0x0f, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
0x2e, 0x4e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_common_net_address_proto_rawDescOnce sync.Once
file_common_net_address_proto_rawDescData = file_common_net_address_proto_rawDesc
)
func file_common_net_address_proto_rawDescGZIP() []byte {
file_common_net_address_proto_rawDescOnce.Do(func() {
file_common_net_address_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_net_address_proto_rawDescData)
})
return file_common_net_address_proto_rawDescData
}
var file_common_net_address_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_common_net_address_proto_goTypes = []interface{}{
(*IPOrDomain)(nil), // 0: xray.common.net.IPOrDomain
}
var file_common_net_address_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_common_net_address_proto_init() }
func file_common_net_address_proto_init() {
if File_common_net_address_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_common_net_address_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*IPOrDomain); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
file_common_net_address_proto_msgTypes[0].OneofWrappers = []interface{}{
(*IPOrDomain_Ip)(nil),
(*IPOrDomain_Domain)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_common_net_address_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_common_net_address_proto_goTypes,
DependencyIndexes: file_common_net_address_proto_depIdxs,
MessageInfos: file_common_net_address_proto_msgTypes,
}.Build()
File_common_net_address_proto = out.File
file_common_net_address_proto_rawDesc = nil
file_common_net_address_proto_goTypes = nil
file_common_net_address_proto_depIdxs = nil
}

19
common/net/address.proto Normal file
View file

@ -0,0 +1,19 @@
syntax = "proto3";
package xray.common.net;
option csharp_namespace = "Xray.Common.Net";
option go_package = "github.com/xtls/xray-core/v1/common/net";
option java_package = "com.xray.common.net";
option java_multiple_files = true;
// Address of a network host. It may be either an IP address or a domain
// address.
message IPOrDomain {
oneof address {
// IP address. Must by either 4 or 16 bytes.
bytes ip = 1;
// Domain address.
string domain = 2;
}
}

194
common/net/address_test.go Normal file
View file

@ -0,0 +1,194 @@
package net_test
import (
"net"
"testing"
"github.com/google/go-cmp/cmp"
. "github.com/xtls/xray-core/v1/common/net"
)
func TestAddressProperty(t *testing.T) {
type addrProprty struct {
IP []byte
Domain string
Family AddressFamily
String string
}
testCases := []struct {
Input Address
Output addrProprty
}{
{
Input: IPAddress([]byte{byte(1), byte(2), byte(3), byte(4)}),
Output: addrProprty{
IP: []byte{byte(1), byte(2), byte(3), byte(4)},
Family: AddressFamilyIPv4,
String: "1.2.3.4",
},
},
{
Input: IPAddress([]byte{
byte(1), byte(2), byte(3), byte(4),
byte(1), byte(2), byte(3), byte(4),
byte(1), byte(2), byte(3), byte(4),
byte(1), byte(2), byte(3), byte(4),
}),
Output: addrProprty{
IP: []byte{
byte(1), byte(2), byte(3), byte(4),
byte(1), byte(2), byte(3), byte(4),
byte(1), byte(2), byte(3), byte(4),
byte(1), byte(2), byte(3), byte(4),
},
Family: AddressFamilyIPv6,
String: "[102:304:102:304:102:304:102:304]",
},
},
{
Input: IPAddress([]byte{
byte(0), byte(0), byte(0), byte(0),
byte(0), byte(0), byte(0), byte(0),
byte(0), byte(0), byte(255), byte(255),
byte(1), byte(2), byte(3), byte(4),
}),
Output: addrProprty{
IP: []byte{byte(1), byte(2), byte(3), byte(4)},
Family: AddressFamilyIPv4,
String: "1.2.3.4",
},
},
{
Input: DomainAddress("example.com"),
Output: addrProprty{
Domain: "example.com",
Family: AddressFamilyDomain,
String: "example.com",
},
},
{
Input: IPAddress(net.IPv4(1, 2, 3, 4)),
Output: addrProprty{
IP: []byte{byte(1), byte(2), byte(3), byte(4)},
Family: AddressFamilyIPv4,
String: "1.2.3.4",
},
},
{
Input: ParseAddress("[2001:4860:0:2001::68]"),
Output: addrProprty{
IP: []byte{0x20, 0x01, 0x48, 0x60, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68},
Family: AddressFamilyIPv6,
String: "[2001:4860:0:2001::68]",
},
},
{
Input: ParseAddress("::0"),
Output: addrProprty{
IP: AnyIPv6.IP(),
Family: AddressFamilyIPv6,
String: "[::]",
},
},
{
Input: ParseAddress("[::ffff:123.151.71.143]"),
Output: addrProprty{
IP: []byte{123, 151, 71, 143},
Family: AddressFamilyIPv4,
String: "123.151.71.143",
},
},
{
Input: NewIPOrDomain(ParseAddress("example.com")).AsAddress(),
Output: addrProprty{
Domain: "example.com",
Family: AddressFamilyDomain,
String: "example.com",
},
},
{
Input: NewIPOrDomain(ParseAddress("8.8.8.8")).AsAddress(),
Output: addrProprty{
IP: []byte{8, 8, 8, 8},
Family: AddressFamilyIPv4,
String: "8.8.8.8",
},
},
{
Input: NewIPOrDomain(ParseAddress("[2001:4860:0:2001::68]")).AsAddress(),
Output: addrProprty{
IP: []byte{0x20, 0x01, 0x48, 0x60, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68},
Family: AddressFamilyIPv6,
String: "[2001:4860:0:2001::68]",
},
},
}
for _, testCase := range testCases {
actual := addrProprty{
Family: testCase.Input.Family(),
String: testCase.Input.String(),
}
if testCase.Input.Family().IsIP() {
actual.IP = testCase.Input.IP()
} else {
actual.Domain = testCase.Input.Domain()
}
if r := cmp.Diff(actual, testCase.Output); r != "" {
t.Error("for input: ", testCase.Input, ":", r)
}
}
}
func TestInvalidAddressConvertion(t *testing.T) {
panics := func(f func()) (ret bool) {
defer func() {
if r := recover(); r != nil {
ret = true
}
}()
f()
return false
}
testCases := []func(){
func() { ParseAddress("8.8.8.8").Domain() },
func() { ParseAddress("2001:4860:0:2001::68").Domain() },
func() { ParseAddress("example.com").IP() },
}
for idx, testCase := range testCases {
if !panics(testCase) {
t.Error("case ", idx, " failed")
}
}
}
func BenchmarkParseAddressIPv4(b *testing.B) {
for i := 0; i < b.N; i++ {
addr := ParseAddress("8.8.8.8")
if addr.Family() != AddressFamilyIPv4 {
panic("not ipv4")
}
}
}
func BenchmarkParseAddressIPv6(b *testing.B) {
for i := 0; i < b.N; i++ {
addr := ParseAddress("2001:4860:0:2001::68")
if addr.Family() != AddressFamilyIPv6 {
panic("not ipv6")
}
}
}
func BenchmarkParseAddressDomain(b *testing.B) {
for i := 0; i < b.N; i++ {
addr := ParseAddress("example.com")
if addr.Family() != AddressFamilyDomain {
panic("not domain")
}
}
}

162
common/net/connection.go Normal file
View file

@ -0,0 +1,162 @@
// +build !confonly
package net
import (
"io"
"net"
"time"
"github.com/xtls/xray-core/v1/common"
"github.com/xtls/xray-core/v1/common/buf"
"github.com/xtls/xray-core/v1/common/signal/done"
)
type ConnectionOption func(*connection)
func ConnectionLocalAddr(a net.Addr) ConnectionOption {
return func(c *connection) {
c.local = a
}
}
func ConnectionRemoteAddr(a net.Addr) ConnectionOption {
return func(c *connection) {
c.remote = a
}
}
func ConnectionInput(writer io.Writer) ConnectionOption {
return func(c *connection) {
c.writer = buf.NewWriter(writer)
}
}
func ConnectionInputMulti(writer buf.Writer) ConnectionOption {
return func(c *connection) {
c.writer = writer
}
}
func ConnectionOutput(reader io.Reader) ConnectionOption {
return func(c *connection) {
c.reader = &buf.BufferedReader{Reader: buf.NewReader(reader)}
}
}
func ConnectionOutputMulti(reader buf.Reader) ConnectionOption {
return func(c *connection) {
c.reader = &buf.BufferedReader{Reader: reader}
}
}
func ConnectionOutputMultiUDP(reader buf.Reader) ConnectionOption {
return func(c *connection) {
c.reader = &buf.BufferedReader{
Reader: reader,
Spliter: buf.SplitFirstBytes,
}
}
}
func ConnectionOnClose(n io.Closer) ConnectionOption {
return func(c *connection) {
c.onClose = n
}
}
func NewConnection(opts ...ConnectionOption) net.Conn {
c := &connection{
done: done.New(),
local: &net.TCPAddr{
IP: []byte{0, 0, 0, 0},
Port: 0,
},
remote: &net.TCPAddr{
IP: []byte{0, 0, 0, 0},
Port: 0,
},
}
for _, opt := range opts {
opt(c)
}
return c
}
type connection struct {
reader *buf.BufferedReader
writer buf.Writer
done *done.Instance
onClose io.Closer
local Addr
remote Addr
}
func (c *connection) Read(b []byte) (int, error) {
return c.reader.Read(b)
}
// ReadMultiBuffer implements buf.Reader.
func (c *connection) ReadMultiBuffer() (buf.MultiBuffer, error) {
return c.reader.ReadMultiBuffer()
}
// Write implements net.Conn.Write().
func (c *connection) Write(b []byte) (int, error) {
if c.done.Done() {
return 0, io.ErrClosedPipe
}
l := len(b)
mb := make(buf.MultiBuffer, 0, l/buf.Size+1)
mb = buf.MergeBytes(mb, b)
return l, c.writer.WriteMultiBuffer(mb)
}
func (c *connection) WriteMultiBuffer(mb buf.MultiBuffer) error {
if c.done.Done() {
buf.ReleaseMulti(mb)
return io.ErrClosedPipe
}
return c.writer.WriteMultiBuffer(mb)
}
// Close implements net.Conn.Close().
func (c *connection) Close() error {
common.Must(c.done.Close())
common.Interrupt(c.reader)
common.Close(c.writer)
if c.onClose != nil {
return c.onClose.Close()
}
return nil
}
// LocalAddr implements net.Conn.LocalAddr().
func (c *connection) LocalAddr() net.Addr {
return c.local
}
// RemoteAddr implements net.Conn.RemoteAddr().
func (c *connection) RemoteAddr() net.Addr {
return c.remote
}
// SetDeadline implements net.Conn.SetDeadline().
func (c *connection) SetDeadline(t time.Time) error {
return nil
}
// SetReadDeadline implements net.Conn.SetReadDeadline().
func (c *connection) SetReadDeadline(t time.Time) error {
return nil
}
// SetWriteDeadline implements net.Conn.SetWriteDeadline().
func (c *connection) SetWriteDeadline(t time.Time) error {
return nil
}

126
common/net/destination.go Normal file
View file

@ -0,0 +1,126 @@
package net
import (
"net"
"strings"
)
// Destination represents a network destination including address and protocol (tcp / udp).
type Destination struct {
Address Address
Port Port
Network Network
}
// DestinationFromAddr generates a Destination from a net address.
func DestinationFromAddr(addr net.Addr) Destination {
switch addr := addr.(type) {
case *net.TCPAddr:
return TCPDestination(IPAddress(addr.IP), Port(addr.Port))
case *net.UDPAddr:
return UDPDestination(IPAddress(addr.IP), Port(addr.Port))
case *net.UnixAddr:
return UnixDestination(DomainAddress(addr.Name))
default:
panic("Net: Unknown address type.")
}
}
// ParseDestination converts a destination from its string presentation.
func ParseDestination(dest string) (Destination, error) {
d := Destination{
Address: AnyIP,
Port: Port(0),
}
if strings.HasPrefix(dest, "tcp:") {
d.Network = Network_TCP
dest = dest[4:]
} else if strings.HasPrefix(dest, "udp:") {
d.Network = Network_UDP
dest = dest[4:]
} else if strings.HasPrefix(dest, "unix:") {
d = UnixDestination(DomainAddress(dest[5:]))
return d, nil
}
hstr, pstr, err := SplitHostPort(dest)
if err != nil {
return d, err
}
if len(hstr) > 0 {
d.Address = ParseAddress(hstr)
}
if len(pstr) > 0 {
port, err := PortFromString(pstr)
if err != nil {
return d, err
}
d.Port = port
}
return d, nil
}
// TCPDestination creates a TCP destination with given address
func TCPDestination(address Address, port Port) Destination {
return Destination{
Network: Network_TCP,
Address: address,
Port: port,
}
}
// UDPDestination creates a UDP destination with given address
func UDPDestination(address Address, port Port) Destination {
return Destination{
Network: Network_UDP,
Address: address,
Port: port,
}
}
// UnixDestination creates a Unix destination with given address
func UnixDestination(address Address) Destination {
return Destination{
Network: Network_UNIX,
Address: address,
}
}
// NetAddr returns the network address in this Destination in string form.
func (d Destination) NetAddr() string {
addr := ""
if d.Network == Network_TCP || d.Network == Network_UDP {
addr = d.Address.String() + ":" + d.Port.String()
} else if d.Network == Network_UNIX {
addr = d.Address.String()
}
return addr
}
// String returns the strings form of this Destination.
func (d Destination) String() string {
prefix := "unknown:"
switch d.Network {
case Network_TCP:
prefix = "tcp:"
case Network_UDP:
prefix = "udp:"
case Network_UNIX:
prefix = "unix:"
}
return prefix + d.NetAddr()
}
// IsValid returns true if this Destination is valid.
func (d Destination) IsValid() bool {
return d.Network != Network_Unknown
}
// AsDestination converts current Endpoint into Destination.
func (p *Endpoint) AsDestination() Destination {
return Destination{
Network: p.Network,
Address: p.Address.AsAddress(),
Port: Port(p.Port),
}
}

View file

@ -0,0 +1,185 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.14.0
// source: common/net/destination.proto
package net
import (
proto "github.com/golang/protobuf/proto"
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)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// Endpoint of a network connection.
type Endpoint struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Network Network `protobuf:"varint,1,opt,name=network,proto3,enum=xray.common.net.Network" json:"network,omitempty"`
Address *IPOrDomain `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"`
Port uint32 `protobuf:"varint,3,opt,name=port,proto3" json:"port,omitempty"`
}
func (x *Endpoint) Reset() {
*x = Endpoint{}
if protoimpl.UnsafeEnabled {
mi := &file_common_net_destination_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Endpoint) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Endpoint) ProtoMessage() {}
func (x *Endpoint) ProtoReflect() protoreflect.Message {
mi := &file_common_net_destination_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Endpoint.ProtoReflect.Descriptor instead.
func (*Endpoint) Descriptor() ([]byte, []int) {
return file_common_net_destination_proto_rawDescGZIP(), []int{0}
}
func (x *Endpoint) GetNetwork() Network {
if x != nil {
return x.Network
}
return Network_Unknown
}
func (x *Endpoint) GetAddress() *IPOrDomain {
if x != nil {
return x.Address
}
return nil
}
func (x *Endpoint) GetPort() uint32 {
if x != nil {
return x.Port
}
return 0
}
var File_common_net_destination_proto protoreflect.FileDescriptor
var file_common_net_destination_proto_rawDesc = []byte{
0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x64, 0x65, 0x73,
0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x1a,
0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65, 0x74, 0x77,
0x6f, 0x72, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x22, 0x89, 0x01, 0x0a, 0x08, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
0x12, 0x32, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0e, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74,
0x77, 0x6f, 0x72, 0x6b, 0x12, 0x35, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61,
0x69, 0x6e, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70,
0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x42,
0x52, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x27, 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, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65,
0x74, 0xaa, 0x02, 0x0f, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
0x4e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_common_net_destination_proto_rawDescOnce sync.Once
file_common_net_destination_proto_rawDescData = file_common_net_destination_proto_rawDesc
)
func file_common_net_destination_proto_rawDescGZIP() []byte {
file_common_net_destination_proto_rawDescOnce.Do(func() {
file_common_net_destination_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_net_destination_proto_rawDescData)
})
return file_common_net_destination_proto_rawDescData
}
var file_common_net_destination_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_common_net_destination_proto_goTypes = []interface{}{
(*Endpoint)(nil), // 0: xray.common.net.Endpoint
(Network)(0), // 1: xray.common.net.Network
(*IPOrDomain)(nil), // 2: xray.common.net.IPOrDomain
}
var file_common_net_destination_proto_depIdxs = []int32{
1, // 0: xray.common.net.Endpoint.network:type_name -> xray.common.net.Network
2, // 1: xray.common.net.Endpoint.address:type_name -> xray.common.net.IPOrDomain
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_common_net_destination_proto_init() }
func file_common_net_destination_proto_init() {
if File_common_net_destination_proto != nil {
return
}
file_common_net_network_proto_init()
file_common_net_address_proto_init()
if !protoimpl.UnsafeEnabled {
file_common_net_destination_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Endpoint); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_common_net_destination_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_common_net_destination_proto_goTypes,
DependencyIndexes: file_common_net_destination_proto_depIdxs,
MessageInfos: file_common_net_destination_proto_msgTypes,
}.Build()
File_common_net_destination_proto = out.File
file_common_net_destination_proto_rawDesc = nil
file_common_net_destination_proto_goTypes = nil
file_common_net_destination_proto_depIdxs = nil
}

View file

@ -0,0 +1,17 @@
syntax = "proto3";
package xray.common.net;
option csharp_namespace = "Xray.Common.Net";
option go_package = "github.com/xtls/xray-core/v1/common/net";
option java_package = "com.xray.common.net";
option java_multiple_files = true;
import "common/net/network.proto";
import "common/net/address.proto";
// Endpoint of a network connection.
message Endpoint {
Network network = 1;
IPOrDomain address = 2;
uint32 port = 3;
}

View file

@ -0,0 +1,111 @@
package net_test
import (
"testing"
"github.com/google/go-cmp/cmp"
. "github.com/xtls/xray-core/v1/common/net"
)
func TestDestinationProperty(t *testing.T) {
testCases := []struct {
Input Destination
Network Network
String string
NetString string
}{
{
Input: TCPDestination(IPAddress([]byte{1, 2, 3, 4}), 80),
Network: Network_TCP,
String: "tcp:1.2.3.4:80",
NetString: "1.2.3.4:80",
},
{
Input: UDPDestination(IPAddress([]byte{0x20, 0x01, 0x48, 0x60, 0x48, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88}), 53),
Network: Network_UDP,
String: "udp:[2001:4860:4860::8888]:53",
NetString: "[2001:4860:4860::8888]:53",
},
{
Input: UnixDestination(DomainAddress("/tmp/test.sock")),
Network: Network_UNIX,
String: "unix:/tmp/test.sock",
NetString: "/tmp/test.sock",
},
}
for _, testCase := range testCases {
dest := testCase.Input
if r := cmp.Diff(dest.Network, testCase.Network); r != "" {
t.Error("unexpected Network in ", dest.String(), ": ", r)
}
if r := cmp.Diff(dest.String(), testCase.String); r != "" {
t.Error(r)
}
if r := cmp.Diff(dest.NetAddr(), testCase.NetString); r != "" {
t.Error(r)
}
}
}
func TestDestinationParse(t *testing.T) {
cases := []struct {
Input string
Output Destination
Error bool
}{
{
Input: "tcp:127.0.0.1:80",
Output: TCPDestination(LocalHostIP, Port(80)),
},
{
Input: "udp:8.8.8.8:53",
Output: UDPDestination(IPAddress([]byte{8, 8, 8, 8}), Port(53)),
},
{
Input: "unix:/tmp/test.sock",
Output: UnixDestination(DomainAddress("/tmp/test.sock")),
},
{
Input: "8.8.8.8:53",
Output: Destination{
Address: IPAddress([]byte{8, 8, 8, 8}),
Port: Port(53),
},
},
{
Input: ":53",
Output: Destination{
Address: AnyIP,
Port: Port(53),
},
},
{
Input: "8.8.8.8",
Error: true,
},
{
Input: "8.8.8.8:http",
Error: true,
},
{
Input: "/tmp/test.sock",
Error: true,
},
}
for _, testcase := range cases {
d, err := ParseDestination(testcase.Input)
if !testcase.Error {
if err != nil {
t.Error("for test case: ", testcase.Input, " expected no error, but got ", err)
}
if d != testcase.Output {
t.Error("for test case: ", testcase.Input, " expected output: ", testcase.Output.String(), " but got ", d.String())
}
} else if err == nil {
t.Error("for test case: ", testcase.Input, " expected error, but got nil")
}
}
}

View file

@ -0,0 +1,9 @@
package net
import "github.com/xtls/xray-core/v1/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

4
common/net/net.go Normal file
View file

@ -0,0 +1,4 @@
// Package net is a drop-in replacement to Golang's net package, with some more functionalities.
package net // import "github.com/xtls/xray-core/v1/common/net"
//go:generate go run github.com/xtls/xray-core/v1/common/errors/errorgen

24
common/net/network.go Normal file
View file

@ -0,0 +1,24 @@
package net
func (n Network) SystemString() string {
switch n {
case Network_TCP:
return "tcp"
case Network_UDP:
return "udp"
case Network_UNIX:
return "unix"
default:
return "unknown"
}
}
// HasNetwork returns true if the network list has a certain network.
func HasNetwork(list []Network, network Network) bool {
for _, value := range list {
if value == network {
return true
}
}
return false
}

219
common/net/network.pb.go Normal file
View file

@ -0,0 +1,219 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.14.0
// source: common/net/network.proto
package net
import (
proto "github.com/golang/protobuf/proto"
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)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Network int32
const (
Network_Unknown Network = 0
// Deprecated: Do not use.
Network_RawTCP Network = 1
Network_TCP Network = 2
Network_UDP Network = 3
Network_UNIX Network = 4
)
// Enum value maps for Network.
var (
Network_name = map[int32]string{
0: "Unknown",
1: "RawTCP",
2: "TCP",
3: "UDP",
4: "UNIX",
}
Network_value = map[string]int32{
"Unknown": 0,
"RawTCP": 1,
"TCP": 2,
"UDP": 3,
"UNIX": 4,
}
)
func (x Network) Enum() *Network {
p := new(Network)
*p = x
return p
}
func (x Network) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (Network) Descriptor() protoreflect.EnumDescriptor {
return file_common_net_network_proto_enumTypes[0].Descriptor()
}
func (Network) Type() protoreflect.EnumType {
return &file_common_net_network_proto_enumTypes[0]
}
func (x Network) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use Network.Descriptor instead.
func (Network) EnumDescriptor() ([]byte, []int) {
return file_common_net_network_proto_rawDescGZIP(), []int{0}
}
// NetworkList is a list of Networks.
type NetworkList struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Network []Network `protobuf:"varint,1,rep,packed,name=network,proto3,enum=xray.common.net.Network" json:"network,omitempty"`
}
func (x *NetworkList) Reset() {
*x = NetworkList{}
if protoimpl.UnsafeEnabled {
mi := &file_common_net_network_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *NetworkList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NetworkList) ProtoMessage() {}
func (x *NetworkList) ProtoReflect() protoreflect.Message {
mi := &file_common_net_network_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NetworkList.ProtoReflect.Descriptor instead.
func (*NetworkList) Descriptor() ([]byte, []int) {
return file_common_net_network_proto_rawDescGZIP(), []int{0}
}
func (x *NetworkList) GetNetwork() []Network {
if x != nil {
return x.Network
}
return nil
}
var File_common_net_network_proto protoreflect.FileDescriptor
var file_common_net_network_proto_rawDesc = []byte{
0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65, 0x74,
0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x22, 0x41, 0x0a, 0x0b, 0x4e,
0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x07, 0x6e, 0x65,
0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x78, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65,
0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2a, 0x42,
0x0a, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b,
0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x06, 0x52, 0x61, 0x77, 0x54, 0x43, 0x50,
0x10, 0x01, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x43, 0x50, 0x10, 0x02, 0x12,
0x07, 0x0a, 0x03, 0x55, 0x44, 0x50, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x55, 0x4e, 0x49, 0x58,
0x10, 0x04, 0x42, 0x52, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x27, 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, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
0x2f, 0x6e, 0x65, 0x74, 0xaa, 0x02, 0x0f, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2e, 0x4e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_common_net_network_proto_rawDescOnce sync.Once
file_common_net_network_proto_rawDescData = file_common_net_network_proto_rawDesc
)
func file_common_net_network_proto_rawDescGZIP() []byte {
file_common_net_network_proto_rawDescOnce.Do(func() {
file_common_net_network_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_net_network_proto_rawDescData)
})
return file_common_net_network_proto_rawDescData
}
var file_common_net_network_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_common_net_network_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_common_net_network_proto_goTypes = []interface{}{
(Network)(0), // 0: xray.common.net.Network
(*NetworkList)(nil), // 1: xray.common.net.NetworkList
}
var file_common_net_network_proto_depIdxs = []int32{
0, // 0: xray.common.net.NetworkList.network:type_name -> xray.common.net.Network
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_common_net_network_proto_init() }
func file_common_net_network_proto_init() {
if File_common_net_network_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_common_net_network_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*NetworkList); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_common_net_network_proto_rawDesc,
NumEnums: 1,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_common_net_network_proto_goTypes,
DependencyIndexes: file_common_net_network_proto_depIdxs,
EnumInfos: file_common_net_network_proto_enumTypes,
MessageInfos: file_common_net_network_proto_msgTypes,
}.Build()
File_common_net_network_proto = out.File
file_common_net_network_proto_rawDesc = nil
file_common_net_network_proto_goTypes = nil
file_common_net_network_proto_depIdxs = nil
}

19
common/net/network.proto Normal file
View file

@ -0,0 +1,19 @@
syntax = "proto3";
package xray.common.net;
option csharp_namespace = "Xray.Common.Net";
option go_package = "github.com/xtls/xray-core/v1/common/net";
option java_package = "com.xray.common.net";
option java_multiple_files = true;
enum Network {
Unknown = 0;
RawTCP = 1 [deprecated = true];
TCP = 2;
UDP = 3;
UNIX = 4;
}
// NetworkList is a list of Networks.
message NetworkList { repeated Network network = 1; }

95
common/net/port.go Normal file
View file

@ -0,0 +1,95 @@
package net
import (
"encoding/binary"
"strconv"
)
// Port represents a network port in TCP and UDP protocol.
type Port uint16
// PortFromBytes converts a byte array to a Port, assuming bytes are in big endian order.
// @unsafe Caller must ensure that the byte array has at least 2 elements.
func PortFromBytes(port []byte) Port {
return Port(binary.BigEndian.Uint16(port))
}
// PortFromInt converts an integer to a Port.
// @error when the integer is not positive or larger then 65535
func PortFromInt(val uint32) (Port, error) {
if val > 65535 {
return Port(0), newError("invalid port range: ", val)
}
return Port(val), nil
}
// PortFromString converts a string to a Port.
// @error when the string is not an integer or the integral value is a not a valid Port.
func PortFromString(s string) (Port, error) {
val, err := strconv.ParseUint(s, 10, 32)
if err != nil {
return Port(0), newError("invalid port range: ", s)
}
return PortFromInt(uint32(val))
}
// Value return the corresponding uint16 value of a Port.
func (p Port) Value() uint16 {
return uint16(p)
}
// String returns the string presentation of a Port.
func (p Port) String() string {
return strconv.Itoa(int(p))
}
// FromPort returns the beginning port of this PortRange.
func (p *PortRange) FromPort() Port {
return Port(p.From)
}
// ToPort returns the end port of this PortRange.
func (p *PortRange) ToPort() Port {
return Port(p.To)
}
// Contains returns true if the given port is within the range of a PortRange.
func (p *PortRange) Contains(port Port) bool {
return p.FromPort() <= port && port <= p.ToPort()
}
// SinglePortRange returns a PortRange contains a single port.
func SinglePortRange(p Port) *PortRange {
return &PortRange{
From: uint32(p),
To: uint32(p),
}
}
type MemoryPortRange struct {
From Port
To Port
}
func (r MemoryPortRange) Contains(port Port) bool {
return r.From <= port && port <= r.To
}
type MemoryPortList []MemoryPortRange
func PortListFromProto(l *PortList) MemoryPortList {
mpl := make(MemoryPortList, 0, len(l.Range))
for _, r := range l.Range {
mpl = append(mpl, MemoryPortRange{From: Port(r.From), To: Port(r.To)})
}
return mpl
}
func (mpl MemoryPortList) Contains(port Port) bool {
for _, pr := range mpl {
if pr.Contains(port) {
return true
}
}
return false
}

230
common/net/port.pb.go Normal file
View file

@ -0,0 +1,230 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.14.0
// source: common/net/port.proto
package net
import (
proto "github.com/golang/protobuf/proto"
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)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// PortRange represents a range of ports.
type PortRange struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// The port that this range starts from.
From uint32 `protobuf:"varint,1,opt,name=From,proto3" json:"From,omitempty"`
// The port that this range ends with (inclusive).
To uint32 `protobuf:"varint,2,opt,name=To,proto3" json:"To,omitempty"`
}
func (x *PortRange) Reset() {
*x = PortRange{}
if protoimpl.UnsafeEnabled {
mi := &file_common_net_port_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PortRange) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PortRange) ProtoMessage() {}
func (x *PortRange) ProtoReflect() protoreflect.Message {
mi := &file_common_net_port_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PortRange.ProtoReflect.Descriptor instead.
func (*PortRange) Descriptor() ([]byte, []int) {
return file_common_net_port_proto_rawDescGZIP(), []int{0}
}
func (x *PortRange) GetFrom() uint32 {
if x != nil {
return x.From
}
return 0
}
func (x *PortRange) GetTo() uint32 {
if x != nil {
return x.To
}
return 0
}
// PortList is a list of ports.
type PortList struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Range []*PortRange `protobuf:"bytes,1,rep,name=range,proto3" json:"range,omitempty"`
}
func (x *PortList) Reset() {
*x = PortList{}
if protoimpl.UnsafeEnabled {
mi := &file_common_net_port_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PortList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PortList) ProtoMessage() {}
func (x *PortList) ProtoReflect() protoreflect.Message {
mi := &file_common_net_port_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PortList.ProtoReflect.Descriptor instead.
func (*PortList) Descriptor() ([]byte, []int) {
return file_common_net_port_proto_rawDescGZIP(), []int{1}
}
func (x *PortList) GetRange() []*PortRange {
if x != nil {
return x.Range
}
return nil
}
var File_common_net_port_proto protoreflect.FileDescriptor
var file_common_net_port_proto_rawDesc = []byte{
0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x70, 0x6f, 0x72,
0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x22, 0x2f, 0x0a, 0x09, 0x50, 0x6f, 0x72, 0x74,
0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x46, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0d, 0x52, 0x04, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x54, 0x6f, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x54, 0x6f, 0x22, 0x3c, 0x0a, 0x08, 0x50, 0x6f, 0x72,
0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x30, 0x0a, 0x05, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65,
0x52, 0x05, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x42, 0x52, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x50, 0x01,
0x5a, 0x27, 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, 0x76, 0x31, 0x2f, 0x63,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0xaa, 0x02, 0x0f, 0x58, 0x72, 0x61, 0x79,
0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x33,
}
var (
file_common_net_port_proto_rawDescOnce sync.Once
file_common_net_port_proto_rawDescData = file_common_net_port_proto_rawDesc
)
func file_common_net_port_proto_rawDescGZIP() []byte {
file_common_net_port_proto_rawDescOnce.Do(func() {
file_common_net_port_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_net_port_proto_rawDescData)
})
return file_common_net_port_proto_rawDescData
}
var file_common_net_port_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_common_net_port_proto_goTypes = []interface{}{
(*PortRange)(nil), // 0: xray.common.net.PortRange
(*PortList)(nil), // 1: xray.common.net.PortList
}
var file_common_net_port_proto_depIdxs = []int32{
0, // 0: xray.common.net.PortList.range:type_name -> xray.common.net.PortRange
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_common_net_port_proto_init() }
func file_common_net_port_proto_init() {
if File_common_net_port_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_common_net_port_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*PortRange); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_common_net_port_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*PortList); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_common_net_port_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_common_net_port_proto_goTypes,
DependencyIndexes: file_common_net_port_proto_depIdxs,
MessageInfos: file_common_net_port_proto_msgTypes,
}.Build()
File_common_net_port_proto = out.File
file_common_net_port_proto_rawDesc = nil
file_common_net_port_proto_goTypes = nil
file_common_net_port_proto_depIdxs = nil
}

20
common/net/port.proto Normal file
View file

@ -0,0 +1,20 @@
syntax = "proto3";
package xray.common.net;
option csharp_namespace = "Xray.Common.Net";
option go_package = "github.com/xtls/xray-core/v1/common/net";
option java_package = "com.xray.common.net";
option java_multiple_files = true;
// PortRange represents a range of ports.
message PortRange {
// The port that this range starts from.
uint32 From = 1;
// The port that this range ends with (inclusive).
uint32 To = 2;
}
// PortList is a list of ports.
message PortList {
repeated PortRange range = 1;
}

18
common/net/port_test.go Normal file
View file

@ -0,0 +1,18 @@
package net_test
import (
"testing"
. "github.com/xtls/xray-core/v1/common/net"
)
func TestPortRangeContains(t *testing.T) {
portRange := &PortRange{
From: 53,
To: 53,
}
if !portRange.Contains(Port(53)) {
t.Error("expected port range containing 53, but actually not")
}
}

61
common/net/system.go Normal file
View file

@ -0,0 +1,61 @@
package net
import "net"
// DialTCP is an alias of net.DialTCP.
var DialTCP = net.DialTCP
var DialUDP = net.DialUDP
var DialUnix = net.DialUnix
var Dial = net.Dial
type ListenConfig = net.ListenConfig
var Listen = net.Listen
var ListenTCP = net.ListenTCP
var ListenUDP = net.ListenUDP
var ListenUnix = net.ListenUnix
var LookupIP = net.LookupIP
var FileConn = net.FileConn
// ParseIP is an alias of net.ParseIP
var ParseIP = net.ParseIP
var SplitHostPort = net.SplitHostPort
var CIDRMask = net.CIDRMask
type Addr = net.Addr
type Conn = net.Conn
type PacketConn = net.PacketConn
type TCPAddr = net.TCPAddr
type TCPConn = net.TCPConn
type UDPAddr = net.UDPAddr
type UDPConn = net.UDPConn
type UnixAddr = net.UnixAddr
type UnixConn = net.UnixConn
// IP is an alias for net.IP.
type IP = net.IP
type IPMask = net.IPMask
type IPNet = net.IPNet
const IPv4len = net.IPv4len
const IPv6len = net.IPv6len
type Error = net.Error
type AddrError = net.AddrError
type Dialer = net.Dialer
type Listener = net.Listener
type TCPListener = net.TCPListener
type UnixListener = net.UnixListener
var ResolveUnixAddr = net.ResolveUnixAddr
var ResolveUDPAddr = net.ResolveUDPAddr
type Resolver = net.Resolver