mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-04-11 17:47:20 +10:00
185 lines
5.5 KiB
Go
185 lines
5.5 KiB
Go
package option
|
|
|
|
import (
|
|
"context"
|
|
"net/netip"
|
|
|
|
C "github.com/sagernet/sing-box/constant"
|
|
E "github.com/sagernet/sing/common/exceptions"
|
|
"github.com/sagernet/sing/common/json"
|
|
"github.com/sagernet/sing/common/json/badjson"
|
|
"github.com/sagernet/sing/common/json/badoption"
|
|
M "github.com/sagernet/sing/common/metadata"
|
|
"github.com/sagernet/sing/service"
|
|
)
|
|
|
|
type RawDNSOptions struct {
|
|
Servers []DNSServerOptions `json:"servers,omitempty"`
|
|
Rules []DNSRule `json:"rules,omitempty"`
|
|
Final string `json:"final,omitempty"`
|
|
ReverseMapping bool `json:"reverse_mapping,omitempty"`
|
|
DNSClientOptions
|
|
}
|
|
|
|
type DNSOptions struct {
|
|
RawDNSOptions
|
|
}
|
|
|
|
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"
|
|
)
|
|
|
|
type removedLegacyDNSOptions struct {
|
|
FakeIP json.RawMessage `json:"fakeip,omitempty"`
|
|
}
|
|
|
|
func (o *DNSOptions) UnmarshalJSONContext(ctx context.Context, content []byte) error {
|
|
var legacyOptions removedLegacyDNSOptions
|
|
err := json.UnmarshalContext(ctx, content, &legacyOptions)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(legacyOptions.FakeIP) != 0 {
|
|
return E.New(legacyDNSFakeIPRemovedMessage)
|
|
}
|
|
return badjson.UnmarshallExcludedContext(ctx, content, legacyOptions, &o.RawDNSOptions)
|
|
}
|
|
|
|
type DNSClientOptions struct {
|
|
Strategy DomainStrategy `json:"strategy,omitempty"`
|
|
DisableCache bool `json:"disable_cache,omitempty"`
|
|
DisableExpire bool `json:"disable_expire,omitempty"`
|
|
IndependentCache bool `json:"independent_cache,omitempty"`
|
|
CacheCapacity uint32 `json:"cache_capacity,omitempty"`
|
|
Optimistic *OptimisticDNSOptions `json:"optimistic,omitempty"`
|
|
ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
|
|
}
|
|
|
|
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))
|
|
}
|
|
|
|
type DNSTransportOptionsRegistry interface {
|
|
CreateOptions(transportType string) (any, bool)
|
|
}
|
|
type _DNSServerOptions struct {
|
|
Type string `json:"type,omitempty"`
|
|
Tag string `json:"tag,omitempty"`
|
|
Options any `json:"-"`
|
|
}
|
|
|
|
type DNSServerOptions _DNSServerOptions
|
|
|
|
func (o *DNSServerOptions) MarshalJSONContext(ctx context.Context) ([]byte, error) {
|
|
return badjson.MarshallObjectsContext(ctx, (*_DNSServerOptions)(o), o.Options)
|
|
}
|
|
|
|
func (o *DNSServerOptions) UnmarshalJSONContext(ctx context.Context, content []byte) error {
|
|
err := json.UnmarshalContext(ctx, content, (*_DNSServerOptions)(o))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
registry := service.FromContext[DNSTransportOptionsRegistry](ctx)
|
|
if registry == nil {
|
|
return E.New("missing DNS transport options registry in context")
|
|
}
|
|
var options any
|
|
switch o.Type {
|
|
case "", C.DNSTypeLegacy:
|
|
return E.New(legacyDNSServerRemovedMessage)
|
|
default:
|
|
var loaded bool
|
|
options, loaded = registry.CreateOptions(o.Type)
|
|
if !loaded {
|
|
return E.New("unknown transport type: ", o.Type)
|
|
}
|
|
}
|
|
err = badjson.UnmarshallExcludedContext(ctx, content, (*_DNSServerOptions)(o), options)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
o.Options = options
|
|
return nil
|
|
}
|
|
|
|
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 {
|
|
return o.Build().IsDomain()
|
|
}
|
|
|
|
func (o *DNSServerAddressOptions) TakeServerOptions() ServerOptions {
|
|
return ServerOptions(*o)
|
|
}
|
|
|
|
func (o *DNSServerAddressOptions) ReplaceServerOptions(options ServerOptions) {
|
|
*o = DNSServerAddressOptions(options)
|
|
}
|
|
|
|
type HostsDNSServerOptions struct {
|
|
Path badoption.Listable[string] `json:"path,omitempty"`
|
|
Predefined *badjson.TypedMap[string, badoption.Listable[netip.Addr]] `json:"predefined,omitempty"`
|
|
}
|
|
|
|
type RawLocalDNSServerOptions struct {
|
|
DialerOptions
|
|
}
|
|
|
|
type LocalDNSServerOptions struct {
|
|
RawLocalDNSServerOptions
|
|
PreferGo bool `json:"prefer_go,omitempty"`
|
|
}
|
|
|
|
type RemoteDNSServerOptions struct {
|
|
RawLocalDNSServerOptions
|
|
DNSServerAddressOptions
|
|
}
|
|
|
|
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 {
|
|
Inet4Range *badoption.Prefix `json:"inet4_range,omitempty"`
|
|
Inet6Range *badoption.Prefix `json:"inet6_range,omitempty"`
|
|
}
|
|
|
|
type DHCPDNSServerOptions struct {
|
|
LocalDNSServerOptions
|
|
Interface string `json:"interface,omitempty"`
|
|
}
|