github.com/sagernet/sing-box@v1.9.0-rc.20/option/types.go (about) 1 package option 2 3 import ( 4 "net/http" 5 "net/netip" 6 "strings" 7 "time" 8 9 "github.com/sagernet/sing-dns" 10 E "github.com/sagernet/sing/common/exceptions" 11 F "github.com/sagernet/sing/common/format" 12 "github.com/sagernet/sing/common/json" 13 N "github.com/sagernet/sing/common/network" 14 15 mDNS "github.com/miekg/dns" 16 ) 17 18 type ListenAddress netip.Addr 19 20 func NewListenAddress(addr netip.Addr) *ListenAddress { 21 address := ListenAddress(addr) 22 return &address 23 } 24 25 func (a ListenAddress) MarshalJSON() ([]byte, error) { 26 addr := netip.Addr(a) 27 if !addr.IsValid() { 28 return nil, nil 29 } 30 return json.Marshal(addr.String()) 31 } 32 33 func (a *ListenAddress) UnmarshalJSON(content []byte) error { 34 var value string 35 err := json.Unmarshal(content, &value) 36 if err != nil { 37 return err 38 } 39 addr, err := netip.ParseAddr(value) 40 if err != nil { 41 return err 42 } 43 *a = ListenAddress(addr) 44 return nil 45 } 46 47 func (a *ListenAddress) Build() netip.Addr { 48 if a == nil { 49 return netip.AddrFrom4([4]byte{127, 0, 0, 1}) 50 } 51 return (netip.Addr)(*a) 52 } 53 54 type AddrPrefix netip.Prefix 55 56 func (a AddrPrefix) MarshalJSON() ([]byte, error) { 57 prefix := netip.Prefix(a) 58 if prefix.Bits() == prefix.Addr().BitLen() { 59 return json.Marshal(prefix.Addr().String()) 60 } else { 61 return json.Marshal(prefix.String()) 62 } 63 } 64 65 func (a *AddrPrefix) UnmarshalJSON(content []byte) error { 66 var value string 67 err := json.Unmarshal(content, &value) 68 if err != nil { 69 return err 70 } 71 prefix, prefixErr := netip.ParsePrefix(value) 72 if prefixErr == nil { 73 *a = AddrPrefix(prefix) 74 return nil 75 } 76 addr, addrErr := netip.ParseAddr(value) 77 if addrErr == nil { 78 *a = AddrPrefix(netip.PrefixFrom(addr, addr.BitLen())) 79 return nil 80 } 81 return prefixErr 82 } 83 84 func (a AddrPrefix) Build() netip.Prefix { 85 return netip.Prefix(a) 86 } 87 88 type NetworkList string 89 90 func (v *NetworkList) UnmarshalJSON(content []byte) error { 91 var networkList []string 92 err := json.Unmarshal(content, &networkList) 93 if err != nil { 94 var networkItem string 95 err = json.Unmarshal(content, &networkItem) 96 if err != nil { 97 return err 98 } 99 networkList = []string{networkItem} 100 } 101 for _, networkName := range networkList { 102 switch networkName { 103 case N.NetworkTCP, N.NetworkUDP: 104 break 105 default: 106 return E.New("unknown network: " + networkName) 107 } 108 } 109 *v = NetworkList(strings.Join(networkList, "\n")) 110 return nil 111 } 112 113 func (v NetworkList) Build() []string { 114 if v == "" { 115 return []string{N.NetworkTCP, N.NetworkUDP} 116 } 117 return strings.Split(string(v), "\n") 118 } 119 120 type Listable[T any] []T 121 122 func (l Listable[T]) MarshalJSON() ([]byte, error) { 123 arrayList := []T(l) 124 if len(arrayList) == 1 { 125 return json.Marshal(arrayList[0]) 126 } 127 return json.Marshal(arrayList) 128 } 129 130 func (l *Listable[T]) UnmarshalJSON(content []byte) error { 131 err := json.Unmarshal(content, (*[]T)(l)) 132 if err == nil { 133 return nil 134 } 135 var singleItem T 136 newError := json.Unmarshal(content, &singleItem) 137 if newError != nil { 138 return E.Errors(err, newError) 139 } 140 *l = []T{singleItem} 141 return nil 142 } 143 144 type DomainStrategy dns.DomainStrategy 145 146 func (s DomainStrategy) MarshalJSON() ([]byte, error) { 147 var value string 148 switch dns.DomainStrategy(s) { 149 case dns.DomainStrategyAsIS: 150 value = "" 151 // value = "AsIS" 152 case dns.DomainStrategyPreferIPv4: 153 value = "prefer_ipv4" 154 case dns.DomainStrategyPreferIPv6: 155 value = "prefer_ipv6" 156 case dns.DomainStrategyUseIPv4: 157 value = "ipv4_only" 158 case dns.DomainStrategyUseIPv6: 159 value = "ipv6_only" 160 default: 161 return nil, E.New("unknown domain strategy: ", s) 162 } 163 return json.Marshal(value) 164 } 165 166 func (s *DomainStrategy) UnmarshalJSON(bytes []byte) error { 167 var value string 168 err := json.Unmarshal(bytes, &value) 169 if err != nil { 170 return err 171 } 172 switch value { 173 case "", "as_is": 174 *s = DomainStrategy(dns.DomainStrategyAsIS) 175 case "prefer_ipv4": 176 *s = DomainStrategy(dns.DomainStrategyPreferIPv4) 177 case "prefer_ipv6": 178 *s = DomainStrategy(dns.DomainStrategyPreferIPv6) 179 case "ipv4_only": 180 *s = DomainStrategy(dns.DomainStrategyUseIPv4) 181 case "ipv6_only": 182 *s = DomainStrategy(dns.DomainStrategyUseIPv6) 183 default: 184 return E.New("unknown domain strategy: ", value) 185 } 186 return nil 187 } 188 189 type Duration time.Duration 190 191 func (d Duration) MarshalJSON() ([]byte, error) { 192 return json.Marshal((time.Duration)(d).String()) 193 } 194 195 func (d *Duration) UnmarshalJSON(bytes []byte) error { 196 var value string 197 err := json.Unmarshal(bytes, &value) 198 if err != nil { 199 return err 200 } 201 duration, err := ParseDuration(value) 202 if err != nil { 203 return err 204 } 205 *d = Duration(duration) 206 return nil 207 } 208 209 type DNSQueryType uint16 210 211 func (t DNSQueryType) String() string { 212 typeName, loaded := mDNS.TypeToString[uint16(t)] 213 if loaded { 214 return typeName 215 } 216 return F.ToString(uint16(t)) 217 } 218 219 func (t DNSQueryType) MarshalJSON() ([]byte, error) { 220 typeName, loaded := mDNS.TypeToString[uint16(t)] 221 if loaded { 222 return json.Marshal(typeName) 223 } 224 return json.Marshal(uint16(t)) 225 } 226 227 func (t *DNSQueryType) UnmarshalJSON(bytes []byte) error { 228 var valueNumber uint16 229 err := json.Unmarshal(bytes, &valueNumber) 230 if err == nil { 231 *t = DNSQueryType(valueNumber) 232 return nil 233 } 234 var valueString string 235 err = json.Unmarshal(bytes, &valueString) 236 if err == nil { 237 queryType, loaded := mDNS.StringToType[valueString] 238 if loaded { 239 *t = DNSQueryType(queryType) 240 return nil 241 } 242 } 243 return E.New("unknown DNS query type: ", string(bytes)) 244 } 245 246 func DNSQueryTypeToString(queryType uint16) string { 247 typeName, loaded := mDNS.TypeToString[queryType] 248 if loaded { 249 return typeName 250 } 251 return F.ToString(queryType) 252 } 253 254 type HTTPHeader map[string]Listable[string] 255 256 func (h HTTPHeader) Build() http.Header { 257 header := make(http.Header) 258 for name, values := range h { 259 for _, value := range values { 260 header.Add(name, value) 261 } 262 } 263 return header 264 }