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