gitlab-net-dns 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.gitlab-ci.yml +20 -0
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +3 -0
  6. data/.rubocop_defaults.yml +359 -0
  7. data/.rubocop_todo.yml +207 -0
  8. data/.travis.yml +13 -0
  9. data/CHANGELOG.md +113 -0
  10. data/Gemfile +9 -0
  11. data/LICENSE.txt +56 -0
  12. data/README.md +172 -0
  13. data/Rakefile +38 -0
  14. data/THANKS.rdoc +24 -0
  15. data/bin/console +14 -0
  16. data/demo/check_soa.rb +104 -0
  17. data/demo/threads.rb +18 -0
  18. data/gitlab-net-dns.gemspec +24 -0
  19. data/lib/net/dns.rb +104 -0
  20. data/lib/net/dns/header.rb +705 -0
  21. data/lib/net/dns/names.rb +120 -0
  22. data/lib/net/dns/packet.rb +560 -0
  23. data/lib/net/dns/question.rb +185 -0
  24. data/lib/net/dns/resolver.rb +1214 -0
  25. data/lib/net/dns/resolver/socks.rb +148 -0
  26. data/lib/net/dns/resolver/timeouts.rb +70 -0
  27. data/lib/net/dns/rr.rb +356 -0
  28. data/lib/net/dns/rr/a.rb +114 -0
  29. data/lib/net/dns/rr/aaaa.rb +94 -0
  30. data/lib/net/dns/rr/classes.rb +130 -0
  31. data/lib/net/dns/rr/cname.rb +74 -0
  32. data/lib/net/dns/rr/hinfo.rb +96 -0
  33. data/lib/net/dns/rr/mr.rb +70 -0
  34. data/lib/net/dns/rr/mx.rb +82 -0
  35. data/lib/net/dns/rr/ns.rb +70 -0
  36. data/lib/net/dns/rr/null.rb +50 -0
  37. data/lib/net/dns/rr/ptr.rb +77 -0
  38. data/lib/net/dns/rr/soa.rb +75 -0
  39. data/lib/net/dns/rr/srv.rb +41 -0
  40. data/lib/net/dns/rr/txt.rb +58 -0
  41. data/lib/net/dns/rr/types.rb +191 -0
  42. data/lib/net/dns/version.rb +8 -0
  43. data/spec/fixtures/resolv.conf +4 -0
  44. data/spec/spec_helper.rb +14 -0
  45. data/spec/unit/resolver/dns_timeout_spec.rb +36 -0
  46. data/spec/unit/resolver/tcp_timeout_spec.rb +46 -0
  47. data/spec/unit/resolver/udp_timeout_spec.rb +46 -0
  48. data/test/test_helper.rb +13 -0
  49. data/test/unit/header_test.rb +164 -0
  50. data/test/unit/names_test.rb +21 -0
  51. data/test/unit/packet_test.rb +47 -0
  52. data/test/unit/question_test.rb +81 -0
  53. data/test/unit/resolver_test.rb +114 -0
  54. data/test/unit/rr/a_test.rb +106 -0
  55. data/test/unit/rr/aaaa_test.rb +102 -0
  56. data/test/unit/rr/classes_test.rb +83 -0
  57. data/test/unit/rr/cname_test.rb +90 -0
  58. data/test/unit/rr/hinfo_test.rb +111 -0
  59. data/test/unit/rr/mr_test.rb +99 -0
  60. data/test/unit/rr/mx_test.rb +106 -0
  61. data/test/unit/rr/ns_test.rb +80 -0
  62. data/test/unit/rr/types_test.rb +71 -0
  63. data/test/unit/rr_test.rb +127 -0
  64. metadata +172 -0
@@ -0,0 +1,114 @@
1
+ module Net
2
+ module DNS
3
+ class RR
4
+ #
5
+ # = IPv4 Address Record (A)
6
+ #
7
+ # Class for DNS IPv4 Address (A) resource records.
8
+ #
9
+ # The resource data is an IPv4 (i.e. 32 bit long) address,
10
+ # hold in the instance variable +address+.
11
+ #
12
+ # a = Net::DNS::RR::A.new("localhost.movie.edu. 360 IN A 127.0.0.1")
13
+ #
14
+ # a = Net::DNS::RR::A.new(:name => "localhost.movie.edu.",
15
+ # :ttl => 360,
16
+ # :cls => Net::DNS::IN,
17
+ # :type => Net::DNS::A,
18
+ # :address => "127.0.0.1" )
19
+ #
20
+ # When computing binary data to transmit the RR, the RDATA section is an
21
+ # Internet address expressed as four decimal numbers separated by dots
22
+ # without any embedded space (e.g. "10.2.0.52" or "192.0.5.6").
23
+ #
24
+ class A < RR
25
+ # Gets the current IPv4 address for this record.
26
+ #
27
+ # Returns an instance of IPAddr.
28
+ attr_reader :address
29
+
30
+ # Assigns a new IPv4 address to this record, which can be in the
31
+ # form of a <tt>String</tt> or an <tt>IPAddr</tt> object.
32
+ #
33
+ # Examples
34
+ #
35
+ # a.address = "192.168.0.1"
36
+ # a.address = IPAddr.new("10.0.0.1")
37
+ #
38
+ # Returns the new allocated instance of IPAddr.
39
+ def address=(string_or_ipaddr)
40
+ @address = check_address(string_or_ipaddr)
41
+ build_pack
42
+ @address
43
+ end
44
+
45
+ # Gets the standardized value for this record,
46
+ # represented by the value of <tt>address</tt>.
47
+ #
48
+ # Returns a String.
49
+ def value
50
+ address.to_s
51
+ end
52
+
53
+ private
54
+
55
+ def subclass_new_from_hash(options)
56
+ if options.key?(:address)
57
+ @address = check_address(options[:address])
58
+ elsif options.key?(:rdata)
59
+ @address = check_address(options[:rdata])
60
+ else
61
+ raise ArgumentError, ":address or :rdata field is mandatory"
62
+ end
63
+ end
64
+
65
+ def subclass_new_from_string(str)
66
+ @address = check_address(str)
67
+ end
68
+
69
+ def subclass_new_from_binary(data, offset)
70
+ a, b, c, d = data.unpack("@#{offset} CCCC")
71
+ @address = IPAddr.new("#{a}.#{b}.#{c}.#{d}")
72
+ offset + 4
73
+ end
74
+
75
+ def set_type
76
+ @type = Net::DNS::RR::Types.new("A")
77
+ end
78
+
79
+ def get_inspect
80
+ value
81
+ end
82
+
83
+ def check_address(input)
84
+ address = case input
85
+ when IPAddr
86
+ input
87
+ # Address in numeric form
88
+ when Integer
89
+ IPAddr.new(input, Socket::AF_INET)
90
+ when String
91
+ IPAddr.new(input)
92
+ else
93
+ raise ArgumentError, "Invalid IP address `#{input}'"
94
+ end
95
+
96
+ unless address.ipv4?
97
+ raise(ArgumentError, "Must specify an IPv4 address")
98
+ end
99
+
100
+ address
101
+ end
102
+
103
+ def build_pack
104
+ @address_pack = @address.hton
105
+ @rdlength = @address_pack.size
106
+ end
107
+
108
+ def get_data
109
+ @address_pack
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,94 @@
1
+ module Net
2
+ module DNS
3
+ class RR
4
+ #
5
+ # = IPv6 Address Record (AAAA)
6
+ #
7
+ # Class for DNS IPv6 Address (AAAA) resource records.
8
+ #
9
+ class AAAA < RR
10
+ # Gets the current IPv6 address for this record.
11
+ #
12
+ # Returns an instance of IPAddr.
13
+ attr_reader :address
14
+
15
+ # Assigns a new IPv6 address to this record, which can be in the
16
+ # form of a <tt>String</tt> or an <tt>IPAddr</tt> object.
17
+ #
18
+ # Examples
19
+ #
20
+ # a.address = "192.168.0.1"
21
+ # a.address = IPAddr.new("10.0.0.1")
22
+ #
23
+ # Returns the new allocated instance of IPAddr.
24
+ def address=(string_or_ipaddr)
25
+ @address = check_address(string_or_ipaddr)
26
+ build_pack
27
+ @address
28
+ end
29
+
30
+ # Gets the standardized value for this record,
31
+ # represented by the value of <tt>address</tt>.
32
+ #
33
+ # Returns a String.
34
+ def value
35
+ address.to_s
36
+ end
37
+
38
+ private
39
+
40
+ def subclass_new_from_hash(options)
41
+ if options.key?(:address)
42
+ @address = check_address(options[:address])
43
+ else
44
+ raise ArgumentError, ":address field is mandatory"
45
+ end
46
+ end
47
+
48
+ def subclass_new_from_string(str)
49
+ @address = check_address(str)
50
+ end
51
+
52
+ def subclass_new_from_binary(data, offset)
53
+ tokens = data.unpack("@#{offset} n8")
54
+ @address = IPAddr.new(format("%x:%x:%x:%x:%x:%x:%x:%x", *tokens))
55
+ offset + 16
56
+ end
57
+
58
+ def set_type
59
+ @type = Net::DNS::RR::Types.new("AAAA")
60
+ end
61
+
62
+ def get_inspect
63
+ value
64
+ end
65
+
66
+ def check_address(input)
67
+ address = case input
68
+ when IPAddr
69
+ input
70
+ when String
71
+ IPAddr.new(input)
72
+ else
73
+ raise ArgumentError, "Invalid IP address `#{input}'"
74
+ end
75
+
76
+ unless address.ipv6?
77
+ raise(ArgumentError, "Must specify an IPv6 address")
78
+ end
79
+
80
+ address
81
+ end
82
+
83
+ def build_pack
84
+ @address_pack = @address.hton
85
+ @rdlength = @address_pack.size
86
+ end
87
+
88
+ def get_data
89
+ @address_pack
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,130 @@
1
+ module Net
2
+ module DNS
3
+ class RR
4
+ #
5
+ # = Net::DNS::Classes
6
+ #
7
+ # This is an auxiliary class to handle <tt>Net::DNS::RR</tt>
8
+ # class field in a DNS packet.
9
+ #
10
+ class Classes
11
+ # Hash with the values of each RR class stored with the
12
+ # respective id number.
13
+ CLASSES = {
14
+ 'IN' => 1, # RFC 1035
15
+ 'CH' => 3, # RFC 1035
16
+ 'HS' => 4, # RFC 1035
17
+ 'NONE' => 254, # RFC 2136
18
+ 'ANY' => 255, # RFC 1035
19
+ }.freeze
20
+
21
+ # The default value when class is nil in Resource Records
22
+ @@default = CLASSES["IN"]
23
+
24
+ # Creates a new object representing an RR class. Performs some
25
+ # checks on the argument validity too. Il +cls+ is +nil+, the
26
+ # default value is +ANY+ or the one set with Classes.default=
27
+ def initialize(cls)
28
+ case cls
29
+ when String
30
+ initialize_from_str(cls)
31
+ when Integer
32
+ initialize_from_num(cls)
33
+ when nil
34
+ initialize_from_num(@@default)
35
+ end
36
+
37
+ if @str.nil? || @num.nil?
38
+ raise ArgumentError, "Unable to create a `Classes' from `#{cls}'"
39
+ end
40
+ end
41
+
42
+ # Returns the class in number format
43
+ # (default for normal use)
44
+ #
45
+ # FIXME: inspect must return a String.
46
+ #
47
+ def inspect
48
+ @num
49
+ end
50
+
51
+ # Returns the class in string format,
52
+ # ex. "IN" or "CH" or such a string.
53
+ def to_s
54
+ @str.to_s
55
+ end
56
+
57
+ # Returns the class in numeric format,
58
+ # usable by the pack methods for data transfers.
59
+ def to_i
60
+ @num.to_i
61
+ end
62
+
63
+ def self.default
64
+ @@default
65
+ end
66
+
67
+ # Be able to control the default class to assign when
68
+ # cls argument is +nil+. Default to +IN+
69
+ def self.default=(str)
70
+ if CLASSES[str]
71
+ @@default = CLASSES[str]
72
+ else
73
+ raise ArgumentError, "Unknown class `#{str}'"
74
+ end
75
+ end
76
+
77
+ # Returns whether <tt>cls</tt> is a valid RR class.
78
+ #
79
+ # Net::DNS::RR::Classes.valid?("IN")
80
+ # # => true
81
+ # Net::DNS::RR::Classes.valid?(1)
82
+ # # => true
83
+ # Net::DNS::RR::Classes.valid?("Q")
84
+ # # => false
85
+ # Net::DNS::RR::Classes.valid?(256)
86
+ # # => false
87
+ # Net::DNS::RR::Classes.valid?(Hash.new)
88
+ # # => ArgumentError
89
+ #
90
+ # FIXME: valid? should never raise.
91
+ #
92
+ # ==== Raises
93
+ # ArgumentError:: if <tt>cls</tt> isn't either a String or a Fixnum
94
+ #
95
+ def self.valid?(cls)
96
+ case cls
97
+ when String
98
+ CLASSES.key?(cls)
99
+ when Integer
100
+ CLASSES.invert.key?(cls)
101
+ else
102
+ raise ArgumentError, "Wrong cls class: #{cls.class}"
103
+ end
104
+ end
105
+
106
+ # Gives in output the keys from the +Classes+ hash
107
+ # in a format suited for regexps
108
+ def self.regexp
109
+ CLASSES.keys.sort.join("|")
110
+ end
111
+
112
+ private
113
+
114
+ # Initialize a new instance from a Class name.
115
+ def initialize_from_str(str)
116
+ key = str.to_s.upcase
117
+ @num = CLASSES[key]
118
+ @str = key
119
+ end
120
+
121
+ # Initialize a new instance from the Class value.
122
+ def initialize_from_num(num)
123
+ key = num.to_i
124
+ @num = key
125
+ @str = CLASSES.invert[key]
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,74 @@
1
+ module Net # :nodoc:
2
+ module DNS
3
+ class RR
4
+ #
5
+ # = Canonical Name Record (CNAME)
6
+ #
7
+ # Class for DNS CNAME resource records.
8
+ #
9
+ # A CNAME record maps an alias or nickname to the real or Canonical name
10
+ # which may lie outside the current zone.
11
+ # Canonical means expected or real name.
12
+ #
13
+ class CNAME < RR
14
+ # Gets the canonical name value.
15
+ #
16
+ # Returns a String.
17
+ attr_reader :cname
18
+
19
+ # Gets the standardized value for this record,
20
+ # represented by the value of <tt>cname</tt>.
21
+ #
22
+ # Returns a String.
23
+ def value
24
+ cname.to_s
25
+ end
26
+
27
+ private
28
+
29
+ def subclass_new_from_hash(options)
30
+ if options.key?(:cname)
31
+ @cname = check_name(options[:cname])
32
+ else
33
+ raise ArgumentError, ":cname field is mandatory"
34
+ end
35
+ end
36
+
37
+ def subclass_new_from_string(str)
38
+ @cname = check_name(str)
39
+ end
40
+
41
+ def subclass_new_from_binary(data, offset)
42
+ @cname, offset = dn_expand(data, offset)
43
+ offset
44
+ end
45
+
46
+ def set_type
47
+ @type = Net::DNS::RR::Types.new("CNAME")
48
+ end
49
+
50
+ def get_inspect
51
+ value
52
+ end
53
+
54
+ def check_name(input)
55
+ name = input.to_s
56
+ unless name =~ /(\w\.?)+\s*$/ && name =~ /[a-zA-Z]/
57
+ raise ArgumentError, "Invalid Canonical Name `#{name}'"
58
+ end
59
+
60
+ name
61
+ end
62
+
63
+ def build_pack
64
+ @cname_pack = pack_name(@cname)
65
+ @rdlength = @cname_pack.size
66
+ end
67
+
68
+ def get_data
69
+ @cname_pack
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,96 @@
1
+ module Net # :nodoc:
2
+ module DNS
3
+ class RR
4
+ #
5
+ # = System Information Record (HINFO)
6
+ #
7
+ # Class for DNS HINFO resource records.
8
+ #
9
+ # Allows definition of the Hardware type and Operating System (OS) in use at a host.
10
+ # For security reasons these records are rarely used on public servers.
11
+ # If a space exists in the field it must be enclosed in quotes.
12
+ # Single space between CPU and OS parameters.
13
+ #
14
+ class HINFO < RR
15
+ # Gets the CPU value.
16
+ #
17
+ # Returns a String.
18
+ attr_reader :cpu
19
+
20
+ # Gets the OS value.
21
+ #
22
+ # Returns a String.
23
+ attr_reader :os
24
+
25
+ # Gets the standardized value for this record,
26
+ # represented by the value of <tt>cpu</tt> and <tt>os</tt>.
27
+ #
28
+ # Returns a String.
29
+ def value
30
+ %Q("#{cpu}" "#{os}")
31
+ end
32
+
33
+ # Gets a list of all the attributes for this record.
34
+ #
35
+ # Returns an Array of values.
36
+ def to_a
37
+ [nil, nil, cls.to_s, type.to_s, value]
38
+ end
39
+
40
+ private
41
+
42
+ def subclass_new_from_hash(options)
43
+ if options.key?(:cpu) && options.key?(:os)
44
+ @cpu = options[:cpu]
45
+ @os = options[:os]
46
+ else
47
+ raise ArgumentError, ":cpu and :os fields are mandatory"
48
+ end
49
+ end
50
+
51
+ def subclass_new_from_string(str)
52
+ @cpu, @os = check_hinfo(str)
53
+ end
54
+
55
+ def subclass_new_from_binary(data, offset)
56
+ len = data.unpack("@#{offset} C").first
57
+ offset += 1
58
+ @cpu = data[offset..(offset + len)]
59
+ offset += len
60
+
61
+ len = data.unpack("@#{offset} C").first
62
+ offset += 1
63
+ @os = data[offset..(offset + len)]
64
+ offset += len
65
+ end
66
+
67
+ def set_type
68
+ @type = Net::DNS::RR::Types.new("HINFO")
69
+ end
70
+
71
+ def get_inspect
72
+ value
73
+ end
74
+
75
+ def check_hinfo(input)
76
+ if input.to_s.strip =~ /^(?:["']?(.*?)["']?)\s+(?:["']?(.*?)["']?)$/
77
+ [Regexp.last_match(1), Regexp.last_match(2)]
78
+ else
79
+ raise ArgumentError, "Invalid HINFO Section `#{input}'"
80
+ end
81
+ end
82
+
83
+ def build_pack
84
+ @hinfo_pack = ""
85
+ @hinfo_pack += [cpu.size].pack("C") + cpu
86
+ @hinfo_pack += [os.size].pack("C") + os
87
+ @rdlength = @hinfo_pack.size
88
+ end
89
+
90
+ def get_data
91
+ @hinfo_pack
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end