AsyncDNS-cr  Check-in [c210ddc089]

Overview
Comment:Some cleanups
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: c210ddc089b9b0140f9aa6257c2536755e624bf76b41856ae4cc1ccbd536c53b
User & Date: js on 2021-03-04 02:09:32
Other Links: manifest | tags
Context
2021-03-05
00:59
Initial support for sending the query check-in: b6cfd2fe24 user: js tags: trunk
2021-03-04
02:09
Some cleanups check-in: c210ddc089 user: js tags: trunk
01:03
Initial work on sending a query check-in: baf27b579c user: js tags: trunk
Changes

Modified src/query.cr from [f77640a093] to [67a7ba4afc].

1
2
3
4
5
6



7
8
9
10
11
1
2
3
4
5

6
7
8
9
10
11
12
13





-
+
+
+





require "./dns_class"
require "./rr_type"

module AsyncDNS
  class Query
    getter :name, :class, :type
    getter name : String
    getter class : DNSClass
    getter type : RRType

    def initialize(@name : String, @class : DNSClass, @type : RRType)
    end
  end
end

Modified src/resolver.cr from [e08367333f] to [389b0620fd].

1
2
3
4
5
6
7

8
9
10
11
12
13
14
15


16
17
18
19
20
21
22
23
24
25

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

41
42
43
44
45
46
47
48
49
50
1
2
3
4
5
6

7
8
9
10
11
12



13
14


15
16
17
18
19
20
21

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

37
38
39
40
41
42
43
44
45
46
47






-
+





-
-
-
+
+
-
-







-
+














-
+










require "./rr"
require "./settings"
require "./response"

module AsyncDNS
  class Resolver
    getter :settings
    getter settings : Settings

    enum Error
      NO_NAME_SERVER
    end

    private struct Context
      def initialize(@id : UInt16, @settings : Settings,
                     @block : Response | Error ->)
    private record Context, id : UInt16, settings : Settings,
      block : Response | Error ->
      end
    end

    def initialize
      @settings = Settings.new
      @queries = Hash(UInt16, Context).new
      @tcp_queries = Hash(Socket, Context).new
    end

    def resolve(query, &block : Response | Error ->)
    def resolve(query : Query, &block : Response | Error ->)
      id : UInt16
      while true
        id = Random::Secure.rand(UInt16::MIN..UInt16::MAX)
        break unless @queries.has_key?(id)
      end

      if @settings.nameservers.empty?
        yield Error::NO_NAME_SERVER
        return
      end

      send(Context.new(id, settings.dup, block))
    end

    def send(context : Context)
    private def send(context : Context)
      @queries[context.@id] = context

      # TODO
    end

    def stop
      # TODO
    end
  end
end

Modified src/response.cr from [96a20ec37e] to [05324bedeb].

1
2
3
4
5




6
7
8
9
10
11
1
2
3
4

5
6
7
8
9
10
11
12
13
14




-
+
+
+
+






require "./rr"

module AsyncDNS
  class Response
    property :name, :answer, :authority, :additional
    property name : String
    property answer : Array(RR)
    property authority : Array(RR)
    property additional : Array(RR)

    def initialize(@name : String, @answer : Array(RR), @authority : Array(RR),
                   @additional : Array(RR))
    end
  end
end

Modified src/rr.cr from [c7ffec3a5e] to [2fc5a6484f].

1
2
3
4
5




6
7
8

9
10
11
12

13
14
15


16
17
18
19
20

21
22
23


24
25
26
27
28

29
30
31


32
33
34
35
36


37
38
39


40
41
42
43

44

45
46
47



48
49
50
51
52

53
54
55


56
57
58
59
60

61
62
63


64
65
66
67
68


69
70
71



72
73
74
75




76
77



78
79

80
81
82


83
84
85
86
87




88
89
90
91



92
93
94
95
96

97
98
99


100
101
102
103
1
2
3
4

5
6
7
8
9
10

11
12
13
14

15
16


17
18
19
20
21
22

23
24


25
26
27
28
29
30

31
32


33
34
35
36
37
38

39
40
41


42
43
44
45
46
47
48

49
50


51
52
53
54
55
56
57

58
59


60
61
62
63
64
65

66
67


68
69
70
71
72
73

74
75
76


77
78
79
80
81
82
83
84
85
86
87


88
89
90
91

92
93


94
95
96
97
98
99

100
101
102
103
104



105
106
107
108
109
110
111

112
113


114
115
116
117
118
119




-
+
+
+
+


-
+



-
+

-
-
+
+




-
+

-
-
+
+




-
+

-
-
+
+




-
+
+

-
-
+
+




+
-
+

-
-
+
+
+




-
+

-
-
+
+




-
+

-
-
+
+




-
+
+

-
-
+
+
+




+
+
+
+
-
-
+
+
+

-
+

-
-
+
+




-
+
+
+
+

-
-
-
+
+
+




-
+

-
-
+
+




require "socket"

module AsyncDNS
  abstract struct RR
    property :name, :class, :type, :ttl
    property name : String
    property class : DNSClass
    property type : RRType
    property ttl : UInt32

    def initialize(@name : String, @class : DNSClass, @type : RRType,
                   @ttl : Int32)
                   @ttl : UInt32)
    end

    struct A < RR
      property :address
      property address : Socket::IPAddress

      def initialize(name, @address : Socket::IPAddress, ttl)
        super(name, DNSClass::IN, RRType::A, ttl)
      def initialize(name : String, @address : Socket::IPAddress, ttl : UInt32)
        super(name, :in, :a, ttl)
      end
    end

    struct AAAA < RR
      property :address
      property address : Socket::IPAddress

      def initialize(name, @address : Socket::IPAddress, ttl)
        super(name, DNSClass::IN, RRType::AAAA, ttl)
      def initialize(name : String, @address : Socket::IPAddress, ttl : UInt32)
        super(name, :in, :aaaa, ttl)
      end
    end

    struct CNAME < RR
      property :alias
      property alias : String

      def initialize(name, @alias : String, ttl)
        super(name, DNSClass::IN, RRType::CNAME, ttl)
      def initialize(name : String, @alias : String, ttl : UInt32)
        super(name, :in, :cname, ttl)
      end
    end

    struct HINFO < RR
      property :cpu, :os
      property cpu : String
      property os : String

      def initialize(name, @cpu : String, @os : String, ttl)
        super(name, DNSClass::IN, RRType::HINFO, ttl)
      def initialize(name : String, @cpu : String, @os : String, ttl : UInt32)
        super(name, :in, :hinfo, ttl)
      end
    end

    struct MX < RR
      property preference : UInt16
      property :preference, :mx
      property mx : String

      def initialize(name, @preference : UInt16, @mx : String, ttl)
        super(name, DNSClass::IN, RRType::MX, ttl)
      def initialize(name : String, @preference : UInt16, @mx : String,
                     ttl : UInt32)
        super(name, :in, :mx, ttl)
      end
    end

    struct NS < RR
      property :authority
      property authority : String

      def initialize(name, @authority : String, ttl)
        super(name, DNSClass::IN, RRType::NS, ttl)
      def initialize(name : String, @authority : String, ttl : UInt32)
        super(name, :in, :ns, ttl)
      end
    end

    struct PTR < RR
      property :domain
      property domain : String

      def initialize(name, @domain : String, ttl)
        super(name, DNSClass::IN, RRType::PTR, ttl)
      def initialize(name : String, @domain : String, ttl : UInt32)
        super(name, :in, :ptr, ttl)
      end
    end

    struct RP < RR
      property :mailbox, :domain
      property mailbox : String
      property domain : String

      def initialize(name, @mailbox : String, @domain : String, ttl)
        super(name, DNSClass::IN, RRType::RP, ttl)
      def initialize(name : String, @mailbox : String, @domain : String,
                     ttl : UInt32)
        super(name, :in, :rp, ttl)
      end
    end

    struct SOA < RR
      property primary_ns : String
      property responsible : String
      property serial : UInt32
      property refresh : UInt32
      property :primary_ns, :responsible, :serial, :refresh, :retry,
        :expire, :min_ttl
      property retry : UInt32
      property expire : UInt32
      property min_ttl : UInt32

      def initialize(name, @primary_ns : String, @responsible : String,
      def initialize(name : String, @primary_ns : String, @responsible : String,
                     @serial : UInt32, @refresh : UInt32, @retry : UInt32,
                     @expire : UInt32, @min_ttl : UInt32)
        super(name, DNSClass::IN, RRType::SOA, ttl)
                     @expire : UInt32, @min_ttl : UInt32, ttl : UInt32)
        super(name, :in, :soa, ttl)
      end
    end

    struct SRV < RR
      property :prio, :weight, :target, :port
      property prio : UInt16
      property weight : UInt16
      property target : String
      property port : UInt16

      def initialize(name, @prio : UInt16, @weight : UInt16, @target : String,
                     @port : UInt16, ttl)
        super(name, DNSClass::IN, RRType::SRV, ttl)
      def initialize(name : String, @prio : UInt16, @weight : UInt16,
                     @target : String, @port : UInt16, ttl : UInt32)
        super(name, :in, :srv, ttl)
      end
    end

    struct TXT < RR
      property :text
      property text : Array(String)

      def initialize(name, @text : Array(String), ttl)
        super(name, DNSClass::IN, RRType::TXT)
      def initialize(name : String, @text : Array(String), ttl : UInt32)
        super(name, :in, :txt)
      end
    end
  end
end

Modified src/settings.cr from [a3be16cbc5] to [5585feb972].

1
2
3
4



5
6
7






8
9

10
11
12
13
14
15
16
17

18
19
20
21
22
23
24
25

26
27
28
29
30
31
32
1
2
3
4
5
6
7



8
9
10
11
12
13
14

15
16
17
18
19
20
21
22

23
24
25
26
27
28
29
30

31
32
33
34
35
36
37
38




+
+
+
-
-
-
+
+
+
+
+
+

-
+







-
+







-
+







module AsyncDNS
  class Settings
    @local_domain : String?

    property static_hosts : Hash(String, Array(String))
    property nameservers : Array(String)
    property local_domain : String?
    property :static_hosts, :nameservers, :local_domain, :search_domains,
      :uses_tcp, :reload_period
    getter :timeout, :max_attempts, :abs_num_dots
    property search_domains : Array(String)
    property uses_tcp : Bool
    property reload_period : Time::Span
    getter timeout : Time::Span
    getter max_attempts : Int32
    getter abs_num_dots : Int32

    def timeout=(timeout)
    def timeout=(timeout : Time::Span)
      if timeout < Time::Span.zero
        raise ArgumentError.new("timeout must be positive")
      end

      @timeout = timeout
    end

    def max_attempts=(max_attempts)
    def max_attempts=(max_attempts : Int32)
      if max_attempts < 0
        raise ArgumentError.new("max_attempts must be positive")
      end

      @max_attempts = max_attempts
    end

    def abs_num_dots=(abs_num_dots)
    def abs_num_dots=(abs_num_dots : Int32)
      if abs_num_dots < 0
        raise ArgumentError.new("abs_num_dots must be positive")
      end

      @abs_num_dots = abs_num_dots
    end

56
57
58
59
60
61
62
63

64
65
66
67
68
69
70
62
63
64
65
66
67
68

69
70
71
72
73
74
75
76







-
+







      {% else %}
        {% raise "Your OS is not supported by AsyncDNS" %}
      {% end %}

      @last_reload = Time.monotonic
    end

    def parse_hosts(path)
    private def parse_hosts(path)
      @static_hosts.clear

      File.each_line(path, chomp: true) do |line|
        pos = line.index('#')
        line = line[0, pos] if pos

        split = line.split(/[ \t]/, remove_empty: true)
79
80
81
82
83
84
85
86

87
88
89
90
91
92
93
85
86
87
88
89
90
91

92
93
94
95
96
97
98
99







-
+







          end

          addresses << address
        end
      end
    end

    def parse_resolv_conf(path)
    private def parse_resolv_conf(path)
      @nameservers.clear
      @local_domain = nil
      @search_domains.clear

      File.each_line(path, chomp: true) do |line|
        pos = line.index(/[#;]/)
        line = line[0, pos] if pos