github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/infra/conf/freedom.go (about) 1 package conf 2 3 import ( 4 "net" 5 "strconv" 6 "strings" 7 8 v2net "github.com/xtls/xray-core/common/net" 9 "github.com/xtls/xray-core/common/protocol" 10 "github.com/xtls/xray-core/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 }