package transport import ( "context" "github.com/sagernet/sing-box/adapter" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/dns" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing/common" E "github.com/sagernet/sing/common/exceptions" mDNS "github.com/miekg/dns" ) var _ adapter.DNSTransport = (*PredefinedTransport)(nil) func RegisterPredefined(registry *dns.TransportRegistry) { dns.RegisterTransport[option.PredefinedDNSServerOptions](registry, C.DNSTypePreDefined, NewPredefined) } type PredefinedTransport struct { dns.TransportAdapter responses []*predefinedResponse } type predefinedResponse struct { questions []mDNS.Question answer *mDNS.Msg } func NewPredefined(ctx context.Context, logger log.ContextLogger, tag string, options option.PredefinedDNSServerOptions) (adapter.DNSTransport, error) { var responses []*predefinedResponse for _, response := range options.Responses { questions, msg, err := response.Build() if err != nil { return nil, err } responses = append(responses, &predefinedResponse{ questions: questions, answer: msg, }) } if len(responses) == 0 { return nil, E.New("empty predefined responses") } return &PredefinedTransport{ TransportAdapter: dns.NewTransportAdapter(C.DNSTypePreDefined, tag, nil), responses: responses, }, nil } func (t *PredefinedTransport) Reset() { } func (t *PredefinedTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { for _, response := range t.responses { for _, question := range response.questions { if func() bool { if question.Name == "" && question.Qtype == mDNS.TypeNone { return true } else if question.Name == "" { return common.Any(message.Question, func(it mDNS.Question) bool { return it.Qtype == question.Qtype }) } else if question.Qtype == mDNS.TypeNone { return common.Any(message.Question, func(it mDNS.Question) bool { return it.Name == question.Name }) } else { return common.Contains(message.Question, question) } }() { copyAnswer := *response.answer copyAnswer.Id = message.Id return ©Answer, nil } } } return nil, dns.RCodeNameError }