github.com/xtls/xray-core@v1.8.3/infra/conf/freedom.go (about)

     1  package conf
     2  
     3  import (
     4  	"net"
     5  	"strconv"
     6  	"strings"
     7  
     8  	"github.com/golang/protobuf/proto"
     9  	v2net "github.com/xtls/xray-core/common/net"
    10  	"github.com/xtls/xray-core/common/protocol"
    11  	"github.com/xtls/xray-core/proxy/freedom"
    12  )
    13  
    14  type FreedomConfig struct {
    15  	DomainStrategy string    `json:"domainStrategy"`
    16  	Timeout        *uint32   `json:"timeout"`
    17  	Redirect       string    `json:"redirect"`
    18  	UserLevel      uint32    `json:"userLevel"`
    19  	Fragment       *Fragment `json:"fragment"`
    20  }
    21  
    22  type Fragment struct {
    23  	Packets  string `json:"packets"`
    24  	Length   string `json:"length"`
    25  	Interval string `json:"interval"`
    26  }
    27  
    28  // Build implements Buildable
    29  func (c *FreedomConfig) Build() (proto.Message, error) {
    30  	config := new(freedom.Config)
    31  	config.DomainStrategy = freedom.Config_AS_IS
    32  	switch strings.ToLower(c.DomainStrategy) {
    33  	case "useip", "use_ip", "use-ip":
    34  		config.DomainStrategy = freedom.Config_USE_IP
    35  	case "useip4", "useipv4", "use_ip4", "use_ipv4", "use_ip_v4", "use-ip4", "use-ipv4", "use-ip-v4":
    36  		config.DomainStrategy = freedom.Config_USE_IP4
    37  	case "useip6", "useipv6", "use_ip6", "use_ipv6", "use_ip_v6", "use-ip6", "use-ipv6", "use-ip-v6":
    38  		config.DomainStrategy = freedom.Config_USE_IP6
    39  	}
    40  
    41  	if c.Fragment != nil {
    42  		if len(c.Fragment.Interval) == 0 || len(c.Fragment.Length) == 0 {
    43  			return nil, newError("Invalid interval or length")
    44  		}
    45  		intervalMinMax := strings.Split(c.Fragment.Interval, "-")
    46  		var minInterval, maxInterval int64
    47  		var err, err2 error
    48  		if len(intervalMinMax) == 2 {
    49  			minInterval, err = strconv.ParseInt(intervalMinMax[0], 10, 64)
    50  			maxInterval, err2 = strconv.ParseInt(intervalMinMax[1], 10, 64)
    51  		} else {
    52  			minInterval, err = strconv.ParseInt(intervalMinMax[0], 10, 64)
    53  			maxInterval = minInterval
    54  		}
    55  		if err != nil {
    56  			return nil, newError("Invalid minimum interval: ", err).Base(err)
    57  		}
    58  		if err2 != nil {
    59  			return nil, newError("Invalid maximum interval: ", err2).Base(err2)
    60  		}
    61  
    62  		lengthMinMax := strings.Split(c.Fragment.Length, "-")
    63  		var minLength, maxLength int64
    64  		if len(lengthMinMax) == 2 {
    65  			minLength, err = strconv.ParseInt(lengthMinMax[0], 10, 64)
    66  			maxLength, err2 = strconv.ParseInt(lengthMinMax[1], 10, 64)
    67  
    68  		} else {
    69  			minLength, err = strconv.ParseInt(lengthMinMax[0], 10, 64)
    70  			maxLength = minLength
    71  		}
    72  		if err != nil {
    73  			return nil, newError("Invalid minimum length: ", err).Base(err)
    74  		}
    75  		if err2 != nil {
    76  			return nil, newError("Invalid maximum length: ", err2).Base(err2)
    77  		}
    78  
    79  		if minInterval > maxInterval {
    80  			minInterval, maxInterval = maxInterval, minInterval
    81  		}
    82  		if minLength > maxLength {
    83  			minLength, maxLength = maxLength, minLength
    84  		}
    85  
    86  		config.Fragment = &freedom.Fragment{
    87  			MinInterval: int32(minInterval),
    88  			MaxInterval: int32(maxInterval),
    89  			MinLength:   int32(minLength),
    90  			MaxLength:   int32(maxLength),
    91  		}
    92  
    93  		switch strings.ToLower(c.Fragment.Packets) {
    94  		case "tlshello":
    95  			// TLS Hello Fragmentation (into multiple handshake messages)
    96  			config.Fragment.StartPacket = 0
    97  			config.Fragment.EndPacket = 1
    98  		case "":
    99  			// TCP Segmentation (all packets)
   100  			config.Fragment.StartPacket = 0
   101  			config.Fragment.EndPacket = 0
   102  		default:
   103  			// TCP Segmentation (range)
   104  			packetRange := strings.Split(c.Fragment.Packets, "-")
   105  			var startPacket, endPacket int64
   106  			if len(packetRange) == 2 {
   107  				startPacket, err = strconv.ParseInt(packetRange[0], 10, 64)
   108  				endPacket, err2 = strconv.ParseInt(packetRange[1], 10, 64)
   109  			} else {
   110  				startPacket, err = strconv.ParseInt(packetRange[0], 10, 64)
   111  				endPacket = startPacket
   112  			}
   113  			if err != nil {
   114  				return nil, newError("Invalid start packet: ", err).Base(err)
   115  			}
   116  			if err2 != nil {
   117  				return nil, newError("Invalid end packet: ", err2).Base(err2)
   118  			}
   119  			if startPacket > endPacket {
   120  				return nil, newError("Invalid packet range: ", c.Fragment.Packets)
   121  			}
   122  			if startPacket < 1 {
   123  				return nil, newError("Cannot start from packet 0")
   124  			}
   125  			config.Fragment.StartPacket = int32(startPacket)
   126  			config.Fragment.EndPacket = int32(endPacket)
   127  		}
   128  	}
   129  
   130  	if c.Timeout != nil {
   131  		config.Timeout = *c.Timeout
   132  	}
   133  	config.UserLevel = c.UserLevel
   134  	if len(c.Redirect) > 0 {
   135  		host, portStr, err := net.SplitHostPort(c.Redirect)
   136  		if err != nil {
   137  			return nil, newError("invalid redirect address: ", c.Redirect, ": ", err).Base(err)
   138  		}
   139  		port, err := v2net.PortFromString(portStr)
   140  		if err != nil {
   141  			return nil, newError("invalid redirect port: ", c.Redirect, ": ", err).Base(err)
   142  		}
   143  		config.DestinationOverride = &freedom.DestinationOverride{
   144  			Server: &protocol.ServerEndpoint{
   145  				Port: uint32(port),
   146  			},
   147  		}
   148  
   149  		if len(host) > 0 {
   150  			config.DestinationOverride.Server.Address = v2net.NewIPOrDomain(v2net.ParseAddress(host))
   151  		}
   152  	}
   153  	return config, nil
   154  }