2022-07-06 23:11:48 +08:00
package option
2024-11-18 18:55:34 +08:00
import (
2025-03-16 14:50:44 +08:00
"context"
2024-11-18 18:55:34 +08:00
"net/netip"
2026-07-24 18:15:14 +08:00
"reflect"
2024-11-18 18:55:34 +08:00
2025-03-16 14:50:44 +08:00
C "github.com/sagernet/sing-box/constant"
2026-07-24 18:15:14 +08:00
"github.com/sagernet/sing-box/schema"
2025-03-16 14:50:44 +08:00
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/json"
"github.com/sagernet/sing/common/json/badjson"
2024-11-18 18:55:34 +08:00
"github.com/sagernet/sing/common/json/badoption"
2025-03-16 14:50:44 +08:00
M "github.com/sagernet/sing/common/metadata"
"github.com/sagernet/sing/service"
2024-11-18 18:55:34 +08:00
)
2023-10-21 12:00:00 +08:00
2025-03-16 14:50:44 +08:00
type RawDNSOptions struct {
2025-03-15 15:58:12 +08:00
Servers [] DNSServerOptions `json:"servers,omitempty"`
Rules [] DNSRule `json:"rules,omitempty"`
2026-07-24 18:15:14 +08:00
Final string `json:"final,omitempty" reference:"dns_server"`
2025-03-15 15:58:12 +08:00
ReverseMapping bool `json:"reverse_mapping,omitempty"`
2022-07-06 23:39:17 +08:00
DNSClientOptions
}
2025-03-16 14:50:44 +08:00
type DNSOptions struct {
RawDNSOptions
}
2026-04-07 20:02:32 +08:00
const (
legacyDNSFakeIPRemovedMessage = "legacy DNS fakeip options are deprecated in sing-box 1.12.0 and removed in sing-box 1.14.0, checkout migration: https://sing-box.sagernet.org/migration/#migrate-to-new-dns-server-formats"
legacyDNSServerRemovedMessage = "legacy DNS server formats are deprecated in sing-box 1.12.0 and removed in sing-box 1.14.0, checkout migration: https://sing-box.sagernet.org/migration/#migrate-to-new-dns-server-formats"
)
2025-03-15 15:58:12 +08:00
2026-04-07 20:02:32 +08:00
type removedLegacyDNSOptions struct {
FakeIP json . RawMessage `json:"fakeip,omitempty"`
2025-03-15 15:58:12 +08:00
}
2025-03-16 14:50:44 +08:00
func ( o * DNSOptions ) UnmarshalJSONContext ( ctx context . Context , content [] byte ) error {
2026-04-07 20:02:32 +08:00
var legacyOptions removedLegacyDNSOptions
err := json . UnmarshalContext ( ctx , content , & legacyOptions )
2025-03-16 14:50:44 +08:00
if err != nil {
return err
}
2026-04-07 20:02:32 +08:00
if len ( legacyOptions . FakeIP ) != 0 {
return E . New ( legacyDNSFakeIPRemovedMessage )
2025-02-26 08:59:21 +08:00
}
2026-04-07 20:02:32 +08:00
return badjson . UnmarshallExcludedContext ( ctx , content , legacyOptions , & o . RawDNSOptions )
2022-07-06 23:11:48 +08:00
}
2023-03-25 12:03:23 +08:00
2026-07-24 18:15:14 +08:00
func ( o DNSOptions ) DescribeSchema ( builder schema . Builder ) ( * schema . Node , error ) {
return builder . Define ( "DNS" , func () ( * schema . Node , error ) {
node := schema . StrictObject ()
err := builder . FlattenStruct ( node , reflect . TypeFor [ RawDNSOptions ]())
if err != nil {
return nil , err
}
return node , nil
})
}
2023-03-25 12:03:23 +08:00
type DNSClientOptions struct {
2024-11-18 18:55:34 +08:00
Strategy DomainStrategy `json:"strategy,omitempty"`
2026-04-28 14:29:52 +08:00
Timeout badoption . Duration `json:"timeout,omitempty"`
2024-11-18 18:55:34 +08:00
DisableCache bool `json:"disable_cache,omitempty"`
DisableExpire bool `json:"disable_expire,omitempty"`
2026-07-24 18:15:14 +08:00
IndependentCache bool `json:"independent_cache,omitempty" schema:"omit"`
2024-11-14 12:42:42 +08:00
CacheCapacity uint32 `json:"cache_capacity,omitempty"`
2026-04-11 12:10:52 +08:00
Optimistic * OptimisticDNSOptions `json:"optimistic,omitempty"`
2024-11-18 18:55:34 +08:00
ClientSubnet * badoption . Prefixable `json:"client_subnet,omitempty"`
2023-03-25 12:03:23 +08:00
}
2026-04-11 12:10:52 +08:00
type _OptimisticDNSOptions struct {
Enabled bool `json:"enabled,omitempty"`
Timeout badoption . Duration `json:"timeout,omitempty"`
}
type OptimisticDNSOptions _OptimisticDNSOptions
func ( o OptimisticDNSOptions ) MarshalJSON () ([] byte , error ) {
if o . Timeout == 0 {
return json . Marshal ( o . Enabled )
}
return json . Marshal (( _OptimisticDNSOptions )( o ))
}
func ( o * OptimisticDNSOptions ) UnmarshalJSON ( bytes [] byte ) error {
err := json . Unmarshal ( bytes , & o . Enabled )
if err == nil {
return nil
}
return json . UnmarshalDisallowUnknownFields ( bytes , ( * _OptimisticDNSOptions )( o ))
}
2026-07-24 18:15:14 +08:00
func ( o OptimisticDNSOptions ) DescribeSchema ( builder schema . Builder ) ( * schema . Node , error ) {
objectForm := schema . StrictObject ()
err := builder . FlattenStruct ( objectForm , reflect . TypeFor [ OptimisticDNSOptions ]())
if err != nil {
return nil , err
}
return schema . AnyOf ( schema . BooleanNode (), objectForm ), nil
}
2025-03-16 14:50:44 +08:00
type DNSTransportOptionsRegistry interface {
2026-07-24 18:15:14 +08:00
OptionTypes () [] string
2025-03-16 14:50:44 +08:00
CreateOptions ( transportType string ) ( any , bool )
}
2025-03-15 15:58:12 +08:00
type _DNSServerOptions struct {
2025-03-16 14:50:44 +08:00
Type string `json:"type,omitempty"`
Tag string `json:"tag,omitempty"`
Options any `json:"-"`
}
2025-03-15 15:58:12 +08:00
type DNSServerOptions _DNSServerOptions
2025-03-16 14:50:44 +08:00
2025-03-15 15:58:12 +08:00
func ( o * DNSServerOptions ) MarshalJSONContext ( ctx context . Context ) ([] byte , error ) {
return badjson . MarshallObjectsContext ( ctx , ( * _DNSServerOptions )( o ), o . Options )
2025-03-16 14:50:44 +08:00
}
2025-03-15 15:58:12 +08:00
func ( o * DNSServerOptions ) UnmarshalJSONContext ( ctx context . Context , content [] byte ) error {
err := json . UnmarshalContext ( ctx , content , ( * _DNSServerOptions )( o ))
2025-03-16 14:50:44 +08:00
if err != nil {
return err
}
registry := service . FromContext [ DNSTransportOptionsRegistry ]( ctx )
if registry == nil {
2025-02-26 07:28:42 +08:00
return E . New ( "missing DNS transport options registry in context" )
2025-03-16 14:50:44 +08:00
}
var options any
switch o . Type {
case "" , C . DNSTypeLegacy :
2026-04-07 20:02:32 +08:00
return E . New ( legacyDNSServerRemovedMessage )
2025-03-16 14:50:44 +08:00
default :
var loaded bool
options , loaded = registry . CreateOptions ( o . Type )
if ! loaded {
return E . New ( "unknown transport type: " , o . Type )
}
}
2025-03-15 15:58:12 +08:00
err = badjson . UnmarshallExcludedContext ( ctx , content , ( * _DNSServerOptions )( o ), options )
2025-03-16 14:50:44 +08:00
if err != nil {
return err
}
o . Options = options
return nil
}
2026-07-24 18:15:14 +08:00
func ( o DNSServerOptions ) DescribeSchema ( builder schema . Builder ) ( * schema . Node , error ) {
return builder . Define ( "DNSServer" , func () ( * schema . Node , error ) {
registry := service . FromContext [ DNSTransportOptionsRegistry ]( builder . Context ())
if registry == nil {
return nil , E . New ( "missing DNS transport options registry in context" )
}
return registryUnion ( builder , registry , nil , true )
})
}
2025-03-15 15:58:12 +08:00
type DNSServerAddressOptions struct {
Server string `json:"server"`
ServerPort uint16 `json:"server_port,omitempty"`
}
func ( o DNSServerAddressOptions ) Build () M . Socksaddr {
return M . ParseSocksaddrHostPort ( o . Server , o . ServerPort )
}
func ( o DNSServerAddressOptions ) ServerIsDomain () bool {
2026-03-16 09:36:24 +08:00
return o . Build (). IsDomain ()
2025-03-15 15:58:12 +08:00
}
func ( o * DNSServerAddressOptions ) TakeServerOptions () ServerOptions {
return ServerOptions ( * o )
}
func ( o * DNSServerAddressOptions ) ReplaceServerOptions ( options ServerOptions ) {
* o = DNSServerAddressOptions ( options )
}
2025-03-16 14:50:44 +08:00
type HostsDNSServerOptions struct {
2025-03-10 13:57:59 +08:00
Path badoption . Listable [ string ] `json:"path,omitempty"`
Predefined * badjson . TypedMap [ string , badoption . Listable [ netip . Addr ]] `json:"predefined,omitempty"`
2025-03-16 14:50:44 +08:00
}
2025-08-18 14:19:49 +08:00
type RawLocalDNSServerOptions struct {
2025-03-16 14:50:44 +08:00
DialerOptions
}
2025-08-18 14:19:49 +08:00
type LocalDNSServerOptions struct {
RawLocalDNSServerOptions
2026-04-29 22:26:10 +08:00
PreferGo bool `json:"prefer_go,omitempty"`
NeighborDomain badoption . Listable [ string ] `json:"neighbor_domain,omitempty"`
2025-08-18 14:19:49 +08:00
}
2025-03-16 14:50:44 +08:00
type RemoteDNSServerOptions struct {
2025-08-18 14:19:49 +08:00
RawLocalDNSServerOptions
2025-03-15 15:58:12 +08:00
DNSServerAddressOptions
2025-03-16 14:50:44 +08:00
}
type RemoteTLSDNSServerOptions struct {
RemoteDNSServerOptions
OutboundTLSOptionsContainer
}
type RemoteHTTPSDNSServerOptions struct {
RemoteTLSDNSServerOptions
Path string `json:"path,omitempty"`
Method string `json:"method,omitempty"`
Headers badoption . HTTPHeader `json:"headers,omitempty"`
}
type FakeIPDNSServerOptions struct {
2026-07-24 18:15:14 +08:00
Inet4Range * badoption . Prefix `json:"inet4_range,omitempty" examples:"198.18.0.0/15"`
Inet6Range * badoption . Prefix `json:"inet6_range,omitempty" examples:"fc00::/18"`
2025-03-16 14:50:44 +08:00
}
type DHCPDNSServerOptions struct {
LocalDNSServerOptions
Interface string `json:"interface,omitempty"`
2023-03-25 12:03:23 +08:00
}
2026-04-30 19:42:30 +08:00
type MDNSDNSServerOptions struct {
LocalDNSServerOptions
Interface badoption . Listable [ string ] `json:"interface,omitempty"`
}