mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-07-15 12:29:36 +03:00
Add xhttp transport
This commit is contained in:
181
common/xray/net/address.go
Normal file
181
common/xray/net/address.go
Normal file
@@ -0,0 +1,181 @@
|
||||
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:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DomainAddress creates an Address with given domain.
|
||||
// This is an internal function that forcibly converts a string to domain.
|
||||
// It's mainly used in test files and mux.
|
||||
// Unless you have a specific reason, use net.ParseAddress instead,
|
||||
// as this function does not check whether the input is an IP address.
|
||||
// Otherwise, you will get strange results like domain: 1.1.1.1
|
||||
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()
|
||||
}
|
||||
146
common/xray/net/destination.go
Normal file
146
common/xray/net/destination.go
Normal file
@@ -0,0 +1,146 @@
|
||||
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
|
||||
}
|
||||
|
||||
// RawNetAddr converts a net.Addr from its Destination presentation.
|
||||
func (d Destination) RawNetAddr() net.Addr {
|
||||
var addr net.Addr
|
||||
switch d.Network {
|
||||
case Network_TCP:
|
||||
if d.Address.Family().IsIP() {
|
||||
addr = &net.TCPAddr{
|
||||
IP: d.Address.IP(),
|
||||
Port: int(d.Port),
|
||||
}
|
||||
}
|
||||
case Network_UDP:
|
||||
if d.Address.Family().IsIP() {
|
||||
addr = &net.UDPAddr{
|
||||
IP: d.Address.IP(),
|
||||
Port: int(d.Port),
|
||||
}
|
||||
}
|
||||
case Network_UNIX:
|
||||
if d.Address.Family().IsDomain() {
|
||||
addr = &net.UnixAddr{
|
||||
Name: d.Address.String(),
|
||||
Net: d.Network.SystemString(),
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
13
common/xray/net/net.go
Normal file
13
common/xray/net/net.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package net
|
||||
|
||||
import "time"
|
||||
|
||||
// defines the maximum time an idle TCP session can survive in the tunnel, so
|
||||
// it should be consistent across HTTP versions and with other transports.
|
||||
const ConnIdleTimeout = 300 * time.Second
|
||||
|
||||
// consistent with quic-go
|
||||
const QuicgoH3KeepAlivePeriod = 10 * time.Second
|
||||
|
||||
// consistent with chrome
|
||||
const ChromeH2KeepAlivePeriod = 45 * time.Second
|
||||
33
common/xray/net/network.go
Normal file
33
common/xray/net/network.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package net
|
||||
|
||||
type Network int32
|
||||
|
||||
const (
|
||||
Network_Unknown Network = 0
|
||||
Network_TCP Network = 2
|
||||
Network_UDP Network = 3
|
||||
Network_UNIX Network = 4
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
55
common/xray/net/port.go
Normal file
55
common/xray/net/port.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package net
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"strconv"
|
||||
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
)
|
||||
|
||||
// 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), E.New("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), E.New("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))
|
||||
}
|
||||
|
||||
type MemoryPortRange struct {
|
||||
From Port
|
||||
To Port
|
||||
}
|
||||
|
||||
func (r MemoryPortRange) Contains(port Port) bool {
|
||||
return r.From <= port && port <= r.To
|
||||
}
|
||||
84
common/xray/net/system.go
Normal file
84
common/xray/net/system.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package net
|
||||
|
||||
import "net"
|
||||
|
||||
// DialTCP is an alias of net.DialTCP.
|
||||
var (
|
||||
DialTCP = net.DialTCP
|
||||
DialUDP = net.DialUDP
|
||||
DialUnix = net.DialUnix
|
||||
Dial = net.Dial
|
||||
)
|
||||
|
||||
type ListenConfig = net.ListenConfig
|
||||
|
||||
var (
|
||||
Listen = net.Listen
|
||||
ListenTCP = net.ListenTCP
|
||||
ListenUDP = net.ListenUDP
|
||||
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
|
||||
Conn = net.Conn
|
||||
PacketConn = net.PacketConn
|
||||
)
|
||||
|
||||
type (
|
||||
TCPAddr = net.TCPAddr
|
||||
TCPConn = net.TCPConn
|
||||
)
|
||||
|
||||
type (
|
||||
UDPAddr = net.UDPAddr
|
||||
UDPConn = net.UDPConn
|
||||
)
|
||||
|
||||
type (
|
||||
UnixAddr = net.UnixAddr
|
||||
UnixConn = net.UnixConn
|
||||
)
|
||||
|
||||
// IP is an alias for net.IP.
|
||||
type (
|
||||
IP = net.IP
|
||||
IPMask = net.IPMask
|
||||
IPNet = net.IPNet
|
||||
)
|
||||
|
||||
const (
|
||||
IPv4len = net.IPv4len
|
||||
IPv6len = net.IPv6len
|
||||
)
|
||||
|
||||
type (
|
||||
Error = net.Error
|
||||
AddrError = net.AddrError
|
||||
)
|
||||
|
||||
type (
|
||||
Dialer = net.Dialer
|
||||
Listener = net.Listener
|
||||
TCPListener = net.TCPListener
|
||||
UnixListener = net.UnixListener
|
||||
)
|
||||
|
||||
var (
|
||||
ResolveTCPAddr = net.ResolveTCPAddr
|
||||
ResolveUDPAddr = net.ResolveUDPAddr
|
||||
ResolveUnixAddr = net.ResolveUnixAddr
|
||||
)
|
||||
|
||||
type Resolver = net.Resolver
|
||||
Reference in New Issue
Block a user