github.com/xmplusdev/xmcore@v1.8.11-0.20240412132628-5518b55526af/infra/conf/freedom.go (about)

     1  package conf
     2  
     3  import (
     4  	"net"
     5  	"strconv"
     6  	"strings"
     7  
     8  	v2net "github.com/xmplusdev/xmcore/common/net"
     9  	"github.com/xmplusdev/xmcore/common/protocol"
    10  	"github.com/xmplusdev/xmcore/proxy/freedom"
    11  	"google.golang.org/protobuf/proto"
    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  	ProxyProtocol  uint32    `json:"proxyProtocol"`
    21  }
    22  
    23  type Fragment struct {
    24  	Packets  string `json:"packets"`
    25  	Length   string `json:"length"`
    26  	Interval string `json:"interval"`
    27  }
    28  
    29  // Build implements Buildable
    30  func (c *FreedomConfig) Build() (proto.Message, error) {
    31  	config := new(freedom.Config)
    32  	switch strings.ToLower(c.DomainStrategy) {
    33  	case "asis", "":
    34  		config.DomainStrategy = freedom.Config_AS_IS
    35  	case "useip":
    36  		config.DomainStrategy = freedom.Config_USE_IP
    37  	case "useipv4":
    38  		config.DomainStrategy = freedom.Config_USE_IP4
    39  	case "useipv6":
    40  		config.DomainStrategy = freedom.Config_USE_IP6
    41  	case "useipv4v6":
    42  		config.DomainStrategy = freedom.Config_USE_IP46
    43  	case "useipv6v4":
    44  		config.DomainStrategy = freedom.Config_USE_IP64
    45  	case "forceip":
    46  		config.DomainStrategy = freedom.Config_FORCE_IP
    47  	case "forceipv4":
    48  		config.DomainStrategy = freedom.Config_FORCE_IP4
    49  	case "forceipv6":
    50  		config.DomainStrategy = freedom.Config_FORCE_IP6
    51  	case "forceipv4v6":
    52  		config.DomainStrategy = freedom.Config_FORCE_IP46
    53  	case "forceipv6v4":
    54  		config.DomainStrategy = freedom.Config_FORCE_IP64
    55  	default:
    56  		return nil, newError("unsupported domain strategy: ", c.DomainStrategy)
    57  	}
    58  
    59  	if c.Fragment != nil {
    60  		config.Fragment = new(freedom.Fragment)
    61  		var err, err2 error
    62  
    63  		switch strings.ToLower(c.Fragment.Packets) {
    64  		case "tlshello":
    65  			// TLS Hello Fragmentation (into multiple handshake messages)
    66  			config.Fragment.PacketsFrom = 0
    67  			config.Fragment.PacketsTo = 1
    68  		case "":
    69  			// TCP Segmentation (all packets)
    70  			config.Fragment.PacketsFrom = 0
    71  			config.Fragment.PacketsTo = 0
    72  		default:
    73  			// TCP Segmentation (range)
    74  			packetsFromTo := strings.Split(c.Fragment.Packets, "-")
    75  			if len(packetsFromTo) == 2 {
    76  				config.Fragment.PacketsFrom, err = strconv.ParseUint(packetsFromTo[0], 10, 64)
    77  				config.Fragment.PacketsTo, err2 = strconv.ParseUint(packetsFromTo[1], 10, 64)
    78  			} else {
    79  				config.Fragment.PacketsFrom, err = strconv.ParseUint(packetsFromTo[0], 10, 64)
    80  				config.Fragment.PacketsTo = config.Fragment.PacketsFrom
    81  			}
    82  			if err != nil {
    83  				return nil, newError("Invalid PacketsFrom").Base(err)
    84  			}
    85  			if err2 != nil {
    86  				return nil, newError("Invalid PacketsTo").Base(err2)
    87  			}
    88  			if config.Fragment.PacketsFrom > config.Fragment.PacketsTo {
    89  				config.Fragment.PacketsFrom, config.Fragment.PacketsTo = config.Fragment.PacketsTo, config.Fragment.PacketsFrom
    90  			}
    91  			if config.Fragment.PacketsFrom == 0 {
    92  				return nil, newError("PacketsFrom can't be 0")
    93  			}
    94  		}
    95  
    96  		{
    97  			if c.Fragment.Length == "" {
    98  				return nil, newError("Length can't be empty")
    99  			}
   100  			lengthMinMax := strings.Split(c.Fragment.Length, "-")
   101  			if len(lengthMinMax) == 2 {
   102  				config.Fragment.LengthMin, err = strconv.ParseUint(lengthMinMax[0], 10, 64)
   103  				config.Fragment.LengthMax, err2 = strconv.ParseUint(lengthMinMax[1], 10, 64)
   104  			} else {
   105  				config.Fragment.LengthMin, err = strconv.ParseUint(lengthMinMax[0], 10, 64)
   106  				config.Fragment.LengthMax = config.Fragment.LengthMin
   107  			}
   108  			if err != nil {
   109  				return nil, newError("Invalid LengthMin").Base(err)
   110  			}
   111  			if err2 != nil {
   112  				return nil, newError("Invalid LengthMax").Base(err2)
   113  			}
   114  			if config.Fragment.LengthMin > config.Fragment.LengthMax {
   115  				config.Fragment.LengthMin, config.Fragment.LengthMax = config.Fragment.LengthMax, config.Fragment.LengthMin
   116  			}
   117  			if config.Fragment.LengthMin == 0 {
   118  				return nil, newError("LengthMin can't be 0")
   119  			}
   120  		}
   121  
   122  		{
   123  			if c.Fragment.Interval == "" {
   124  				return nil, newError("Interval can't be empty")
   125  			}
   126  			intervalMinMax := strings.Split(c.Fragment.Interval, "-")
   127  			if len(intervalMinMax) == 2 {
   128  				config.Fragment.IntervalMin, err = strconv.ParseUint(intervalMinMax[0], 10, 64)
   129  				config.Fragment.IntervalMax, err2 = strconv.ParseUint(intervalMinMax[1], 10, 64)
   130  			} else {
   131  				config.Fragment.IntervalMin, err = strconv.ParseUint(intervalMinMax[0], 10, 64)
   132  				config.Fragment.IntervalMax = config.Fragment.IntervalMin
   133  			}
   134  			if err != nil {
   135  				return nil, newError("Invalid IntervalMin").Base(err)
   136  			}
   137  			if err2 != nil {
   138  				return nil, newError("Invalid IntervalMax").Base(err2)
   139  			}
   140  			if config.Fragment.IntervalMin > config.Fragment.IntervalMax {
   141  				config.Fragment.IntervalMin, config.Fragment.IntervalMax = config.Fragment.IntervalMax, config.Fragment.IntervalMin
   142  			}
   143  		}
   144  	}
   145  
   146  	if c.Timeout != nil {
   147  		config.Timeout = *c.Timeout
   148  	}
   149  	config.UserLevel = c.UserLevel
   150  	if len(c.Redirect) > 0 {
   151  		host, portStr, err := net.SplitHostPort(c.Redirect)
   152  		if err != nil {
   153  			return nil, newError("invalid redirect address: ", c.Redirect, ": ", err).Base(err)
   154  		}
   155  		port, err := v2net.PortFromString(portStr)
   156  		if err != nil {
   157  			return nil, newError("invalid redirect port: ", c.Redirect, ": ", err).Base(err)
   158  		}
   159  		config.DestinationOverride = &freedom.DestinationOverride{
   160  			Server: &protocol.ServerEndpoint{
   161  				Port: uint32(port),
   162  			},
   163  		}
   164  
   165  		if len(host) > 0 {
   166  			config.DestinationOverride.Server.Address = v2net.NewIPOrDomain(v2net.ParseAddress(host))
   167  		}
   168  	}
   169  	if c.ProxyProtocol > 0 && c.ProxyProtocol <= 2 {
   170  		config.ProxyProtocol = c.ProxyProtocol
   171  	}
   172  	return config, nil
   173  }