mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-01-31 13:16:53 +00:00
83 lines
2.2 KiB
Go
83 lines
2.2 KiB
Go
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
|
|
}
|