gitlab-net-dns 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
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