From ff4154454e8330a20f31c46698054546478e5457 Mon Sep 17 00:00:00 2001 From: Motalleb Fallahnehzad Date: Sun, 29 Oct 2023 11:15:04 +0330 Subject: [PATCH] [Minor] --- config.new.yaml | 4 +- cord_locator.go | 49 +++++++----- lib/data/answer.go | 80 +++++++++++++++++++ .../internal_messages.go => data/question.go} | 23 ++++-- lib/new_config/config.go | 16 +++- lib/new_config/config_data.go | 28 ++++--- lib/new_config/entry_point/entry_point.go | 28 ++++--- lib/new_config/entry_point/entry_type.go | 25 ++++-- lib/new_config/provider/provider.go | 4 +- lib/new_config/provider/provider_type.go | 15 ++-- 10 files changed, 203 insertions(+), 69 deletions(-) create mode 100644 lib/data/answer.go rename lib/{internal_dns/internal_messages.go => data/question.go} (50%) diff --git a/config.new.yaml b/config.new.yaml index 6e72cab..3f371bf 100644 --- a/config.new.yaml +++ b/config.new.yaml @@ -1,7 +1,7 @@ entry_points: - name: normal # (Optional) port: 53 # (def(53)) - type: raw # (def(raw) | tls | https) + type: udp # (def(udp) | tcp | tls | https) # reserved keys are (https|tls)_params respectively # (Mandatory) uses fallback method to iterate over items @@ -12,7 +12,7 @@ default_providers: # (def(null)) providers: - name: cf # naming providers is mandatory # DNS_SERVER_DEFINITION - type: raw # (tls || https || lua) (if lua addresses should point to lua file) + type: udp # (tls || https || lua) (if lua addresses should point to lua file) addresses: - 1.1.1.1:53 - 1.0.0.1:53 diff --git a/cord_locator.go b/cord_locator.go index 8bf0b92..a4bfc1d 100644 --- a/cord_locator.go +++ b/cord_locator.go @@ -10,8 +10,8 @@ import ( "strings" "syscall" + "github.com/FMotalleb/cord-locator/lib/data" newconfig "github.com/FMotalleb/cord-locator/lib/new_config" - "gopkg.in/yaml.v3" "github.com/FMotalleb/cord-locator/lib/config" "github.com/FMotalleb/cord-locator/lib/utils" @@ -26,22 +26,28 @@ var ( // DNSConfig is the configuration data of the instance DNSConfig config.Config ) -var data = ` -entry_points: - - name: - port: # (def(53)) - type: raw # (def(raw) || tls || https) - -providers: - - name: cf # naming providers is mandatory - # DNS_SERVER_DEFINITION - type: raw # (tls || https || lua) (if lua addresses should point to lua file) - addresses: - - 1.1.1.1:53 - - 1.0.0.1:53 -` + +// var data = ` +// entry_points: +// - name: +// port: # (def(53)) +// type: udp + +// providers: +// - name: cf # naming providers is mandatory +// # DNS_SERVER_DEFINITION +// type: udp +// addresses: +// - 1.1.1.1:53 +// - 1.0.0.1:53 +// ` func main() { + // dd := data.NewAnswer("google.com.", "A", "IN", "216.239.38.120", 80) + rr, _ := dns.NewRR("stackexchange.com. 1800 IN SOA damian.ns.cloudflare.com. dns.cloudflare.com. 2322332295 10000 2400 604800 1800") + // dns. + data.NewAnswerFromRR(rr) + return ctx := context.Background() go func() { select { @@ -56,13 +62,14 @@ func main() { ctx, _ = context.WithCancelCause(ctx) // cancel(errors.New("WTF")) - testConfig := newconfig.ConfigData{} - err := yaml.Unmarshal([]byte(data), &testConfig) - if err != nil { - println(err.Error()) - } + testConfig := newconfig.Data{} + // err := yaml.Unmarshal([]byte(data), &testConfig) + // if err != nil { + // println(err.Error()) + // } confs := make([]string, 0) - for _, item := range testConfig.Providers { + config := testConfig.BuildConfig() + for _, item := range config.Providers { // println(item.Validate().Error()) confs = append(confs, item.String()) } diff --git a/lib/data/answer.go b/lib/data/answer.go new file mode 100644 index 0000000..b7ab150 --- /dev/null +++ b/lib/data/answer.go @@ -0,0 +1,80 @@ +package data + +import ( + "fmt" + "strconv" + "strings" + + "github.com/miekg/dns" +) + +// Answer of a dns query +type Answer struct { + TTL int + Name string + Address string + Type string + Class string +} + +// NewAnswer is generated using given parameters +func NewAnswer(aName string, aType string, aClass string, aAddress string, aTTL int) Answer { + return Answer{ + TTL: aTTL, + Name: aName, + Address: aAddress, + Type: aType, + Class: aClass, + } +} + +func (answer Answer) String() string { + return fmt.Sprintf("%s\t%d\t%s\t%s\t%s", answer.Name, answer.TTL, answer.Class, answer.Type, answer.Address) +} + +func (answer Answer) ToRR() (result dns.RR, err error) { + return dns.NewRR(answer.String()) +} + +func NewAnswerFromString(str string) Answer { + var name string + var aType string + var class string + var address string + var ttl int + lastFilled := 0 + for _, v := range strings.Split(str, "\t") { + if len(v) > 0 { + switch lastFilled { + case 0: + name = v + break + case 1: + ttl, _ = strconv.Atoi(v) + break + case 2: + class = v + break + case 3: + aType = v + break + case 5: + address = v + break + default: + address = address + "\t" + v + + } + lastFilled++ + } + } + if lastFilled != 5 { + panic("unexpected length") + } + + ans := NewAnswer(name, aType, class, address, ttl) + return ans +} +func NewAnswerFromRR(r dns.RR) Answer { + return NewAnswerFromString(r.String()) +} diff --git a/lib/internal_dns/internal_messages.go b/lib/data/question.go similarity index 50% rename from lib/internal_dns/internal_messages.go rename to lib/data/question.go index cf657f9..285cb1e 100644 --- a/lib/internal_dns/internal_messages.go +++ b/lib/data/question.go @@ -5,24 +5,33 @@ import ( "github.com/miekg/dns" ) +// Question of a dns query type Question struct { Type string Class string Name string + From *string } +// NewQuestion built with given parameters +func NewQuestion(qType string, qClass string, qName string) Question { + return Question{ + Type: qType, + Class: qClass, + Name: qName, + } +} + +// GetQuestions from a dns message func GetQuestions(msg *dns.Msg) []Question { + if msg == nil || len(msg.Question) == 0 { return make([]Question, 0) } mapper := func(entry dns.Question) Question { - Qtype := dns.TypeToString[entry.Qtype] - Qclass := dns.ClassToString[entry.Qclass] - return Question{ - Type: Qtype, - Class: Qclass, - Name: entry.Name, - } + qType := dns.TypeToString[entry.Qtype] + qClass := dns.ClassToString[entry.Qclass] + return NewQuestion(qType, qClass, entry.Name) } return iterable.Map[dns.Question, Question](msg.Question, mapper) } diff --git a/lib/new_config/config.go b/lib/new_config/config.go index b878adf..31287ce 100644 --- a/lib/new_config/config.go +++ b/lib/new_config/config.go @@ -5,8 +5,22 @@ import ( "github.com/FMotalleb/cord-locator/lib/new_config/provider" ) +type configFace interface { + GetEntryPoints() []entrypoint.EntryPoint + GetProviders() []provider.Provider +} + // Config of the dns server type Config struct { - EntryPoints []entrypoint.EntryPoint + entryPoints []entrypoint.EntryPoint Providers []provider.Provider + configFace +} + +func (conf Config) GetEntryPoints() []entrypoint.EntryPoint { + return conf.entryPoints +} + +func (conf Config) GetProviders() []provider.Provider { + return conf.Providers } diff --git a/lib/new_config/config_data.go b/lib/new_config/config_data.go index 83f2c4f..8cf75bd 100644 --- a/lib/new_config/config_data.go +++ b/lib/new_config/config_data.go @@ -6,28 +6,36 @@ import ( "github.com/FMotalleb/cord-locator/lib/utils/iterable" ) -// ConfigData representation of yaml config file -type ConfigData struct { - EntryPoints []entrypoint.EntryPointData `yaml:"entry_points,flow"` - Providers []provider.Data `yaml:"providers,flow"` +// Data representation of yaml config file +type Data struct { + EntryPoints []entrypoint.Data `yaml:"entry_points,flow"` + Providers []provider.Data `yaml:"providers,flow"` } -// Finalize the config data and returns new config object with given configuration -func (conf ConfigData) Finalize() Config { +// BuildConfig the config data and returns new config object with given configuration +func (conf Data) BuildConfig() Config { return Config{ - EntryPoints: conf.getEntryPoints(), + entryPoints: conf.getEntryPoints(), Providers: conf.getProviders(), } } -func (conf ConfigData) getEntryPoints() []entrypoint.EntryPoint { - mapper := func(entry entrypoint.EntryPointData) entrypoint.EntryPoint { +func (conf Data) getEntryPoints() []entrypoint.EntryPoint { + mapper := func(entry entrypoint.Data) entrypoint.EntryPoint { + err := entry.Validate() + if err != nil { + panic(err) + } return entrypoint.EntryPoint(entry) } return iterable.Map(conf.EntryPoints, mapper) } -func (conf ConfigData) getProviders() []provider.Provider { +func (conf Data) getProviders() []provider.Provider { mapper := func(entry provider.Data) provider.Provider { + err := entry.Validate() + if err != nil { + panic(err) + } return provider.Provider(entry) } return iterable.Map(conf.Providers, mapper) diff --git a/lib/new_config/entry_point/entry_point.go b/lib/new_config/entry_point/entry_point.go index 785fab4..5415cbb 100644 --- a/lib/new_config/entry_point/entry_point.go +++ b/lib/new_config/entry_point/entry_point.go @@ -7,49 +7,55 @@ import ( "github.com/FMotalleb/cord-locator/lib/validator" ) +type DnsQueryCallback func() + +// EntryPoint of dns server +// indicates where to listen for dns queries type EntryPoint interface { GetName() string GetPort() int - GetType() EntryType + GetType() Type String() string validator.Validatable } -type EntryPointData struct { + +// Data of entry point contains its (optional) name, port and type +type Data struct { Name *string `yaml:"name,omitempty"` Port *int `yaml:"port,omitempty"` Type *string `yaml:"type,omitempty"` EntryPoint } -func (receiver EntryPointData) GetName() string { +func (receiver Data) GetName() string { if receiver.Name == nil { return "" } return *receiver.Name } -func (receiver EntryPointData) GetPort() int { +func (receiver Data) GetPort() int { if receiver.Port == nil { return 53 } return *receiver.Port } -func (receiver EntryPointData) getTypeRaw() string { +func (receiver Data) getTypeRaw() string { if receiver.Type == nil { - return "Raw" + return "UDP" } return *receiver.Type } -func (receiver EntryPointData) GetType() EntryType { +func (receiver Data) GetType() Type { if receiver.Type == nil { - return Raw + return UDP } current := parseType(receiver.Type) return current } -func (receiver EntryPointData) String() string { +func (receiver Data) String() string { buffer := strings.Builder{} buffer.WriteString("EntryPoint(") if len(receiver.GetName()) > 0 { @@ -62,7 +68,7 @@ func (receiver EntryPointData) String() string { buffer.WriteString(")") return buffer.String() } -func (receiver EntryPointData) Validate() error { +func (receiver Data) Validate() error { if receiver.GetPort() < 1 || receiver.GetPort() > 65535 { return validator.NewValidationError( "a valid entry_points.*.port value (1-65535)", @@ -73,7 +79,7 @@ func (receiver EntryPointData) Validate() error { switch parseType(receiver.Type) { case Undefined: return validator.NewValidationError( - "one of (raw | tls | https) in entry_points.*.type", + "one of (udp | tcp | tls | https) in entry_points.*.type", fmt.Sprintf("given type (%s) does not match expected values", receiver.getTypeRaw()), fmt.Sprintf("type value in entrypoint: %s", receiver.GetName())) default: diff --git a/lib/new_config/entry_point/entry_type.go b/lib/new_config/entry_point/entry_type.go index db0b91b..80607fb 100644 --- a/lib/new_config/entry_point/entry_type.go +++ b/lib/new_config/entry_point/entry_type.go @@ -1,21 +1,30 @@ package entrypoint -type EntryType int +// Type indicates the entrypoint connection method +// Typically +// +// UDP: port 53 +// TCP: random port above 1023 +type Type int const ( - Raw EntryType = iota + // UDP dns type normally listens on port 53 and relies on UDP packets, + // this is default dns type supported by almost any device on the planet + UDP Type = iota // TLS // HTTPS + + // Undefined dns type is an unacceptable dns type and provider of this type will be unused Undefined = -1 ) -func parseType(typeName *string) EntryType { +func parseType(typeName *string) Type { if typeName == nil { return Undefined } switch *typeName { - case "raw": - return Raw + case "udp": + return UDP // case "tls": // return TLS // case "https": @@ -24,10 +33,10 @@ func parseType(typeName *string) EntryType { return Undefined } } -func (receiver EntryType) String() string { +func (receiver Type) String() string { switch receiver { - case 0: - return "Raw" + case UDP: + return "UDP" // case 1: // return "TLS" // case 2: diff --git a/lib/new_config/provider/provider.go b/lib/new_config/provider/provider.go index 2d5827b..b58ae5b 100644 --- a/lib/new_config/provider/provider.go +++ b/lib/new_config/provider/provider.go @@ -36,7 +36,7 @@ func (receiver Data) GetName() string { // GetType of this dns provider func (receiver Data) GetType() Type { if receiver.Type == nil { - return Raw + return UDP } current := parseType(receiver.Type) return current @@ -72,7 +72,7 @@ func (receiver Data) Validate() error { switch receiver.GetType() { case Undefined: return validator.NewValidationError( - "one of (raw,lua,https,tls...) in providers.*.type", + "one of (udp,tcp,lua,https,tls...) in providers.*.type", fmt.Sprintf("`%s`", *receiver.Type), fmt.Sprintf("the type in provider: `%s`", receiver.GetName())) default: diff --git a/lib/new_config/provider/provider_type.go b/lib/new_config/provider/provider_type.go index 03a1fec..e2be923 100644 --- a/lib/new_config/provider/provider_type.go +++ b/lib/new_config/provider/provider_type.go @@ -1,11 +1,12 @@ package provider -// Type can be of type Raw,Lua,Tls,HTTPS... +// Type indicates the connection method to the provider type Type int const ( - // Raw dns type which is ipv4:53 udp dns server - Raw Type = iota + // UDP dns type normally listens on port 53 and relies on UDP packets, + // this is default dns type supported by almost any device on the planet + UDP Type = iota // LUA // TLS // HTTPS @@ -22,8 +23,8 @@ func parseType(typeName *string) Type { return Undefined } switch *typeName { - case "raw": - return Raw + case "udp": + return UDP // case "tls": // return TLS // case "https": @@ -34,8 +35,8 @@ func parseType(typeName *string) Type { } func (receiver Type) String() string { switch receiver { - case 0: - return "Raw" + case UDP: + return "Udp" // case 1: // return "TLS" // case 2: