bluemonk-net-dns 0.5.0

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.
@@ -0,0 +1,121 @@
1
+ ##
2
+ #
3
+ # Net::DNS::RR::A
4
+ #
5
+ # $id$
6
+ #
7
+ ##
8
+
9
+ require 'ipaddr'
10
+
11
+ module Net # :nodoc:
12
+ module DNS
13
+
14
+ class RR
15
+
16
+ # =Name
17
+ #
18
+ # Net::DNS::RR::A DNS A resource record
19
+ #
20
+ # =Synopsis
21
+ #
22
+ # require "net/dns/rr"
23
+ #
24
+ # =Description
25
+ #
26
+ # Net::DNS::RR::A is the class to handle resource records of type A, the
27
+ # most common in a DNS query. Its resource data is an IPv4 (i.e. 32 bit
28
+ # long) address, hold in the instance variable +address+.
29
+ # a = Net::DNS::RR::A.new("localhost.movie.edu. 360 IN A 127.0.0.1")
30
+ #
31
+ # a = Net::DNS::RR::A.new(:name => "localhost.movie.edu.",
32
+ # :ttl => 360,
33
+ # :cls => Net::DNS::IN,
34
+ # :type => Net::DNS::A,
35
+ # :address => "127.0.0.1")
36
+ #
37
+ # When computing binary data to trasmit the RR, the RDATA section is an
38
+ # Internet address expressed as four decimal numbers separated by dots
39
+ # without any imbedded spaces (e.g.,"10.2.0.52" or "192.0.5.6").
40
+ #
41
+ class A < RR
42
+ attr_reader :address
43
+
44
+ # Assign to the RR::A object a new IPv4 address, which can be in the
45
+ # form of a string or an IPAddr object
46
+ #
47
+ # a.address = "192.168.0.1"
48
+ # a.address = IPAddr.new("10.0.0.1")
49
+ #
50
+ def address=(addr)
51
+ @address = check_address addr
52
+ build_pack
53
+ end # address=
54
+
55
+ private
56
+
57
+ def check_address(addr)
58
+ address = ""
59
+ case addr
60
+ when String
61
+ address = IPAddr.new addr
62
+ when Integer # Address in numeric form
63
+ tempAddr = [(addr>>24),(addr>>16)&0xFF,(addr>>8)&0xFF,addr&0xFF]
64
+ tempAddr = tempAddr.collect {|x| x.to_s}.join(".")
65
+ address = IPAddr.new tempAddr
66
+ when IPAddr
67
+ address = addr
68
+ else
69
+ raise RRArgumentError, "Unknown address type: #{addr}"
70
+ end
71
+ raise RRArgumentError, "Must specify an IPv4 address" unless address.ipv4?
72
+ address
73
+ rescue ArgumentError
74
+ raise RRArgumentError, "Invalid address #{addr}"
75
+ end
76
+
77
+ def build_pack
78
+ @address_pack = @address.hton
79
+ @rdlength = @address_pack.size
80
+ end
81
+
82
+ def set_type
83
+ @type = Net::DNS::RR::Types.new("A")
84
+ end
85
+
86
+ def get_data
87
+ @address_pack
88
+ end
89
+
90
+ def get_inspect
91
+ "#@address"
92
+ end
93
+
94
+ def subclass_new_from_hash(args)
95
+ if args.has_key? :address
96
+ @address = check_address args[:address]
97
+ elsif args.has_key? :rdata
98
+ @address = check_address args[:rdata]
99
+ else
100
+ # Address field is mandatory
101
+ raise RRArgumentError, ":address field is mandatory but missing"
102
+ end
103
+ end
104
+
105
+ def subclass_new_from_string(str)
106
+ @address = check_address(str)
107
+ end
108
+
109
+ def subclass_new_from_binary(data,offset)
110
+ a,b,c,d = data.unpack("@#{offset} CCCC")
111
+ @address = IPAddr.new "#{a}.#{b}.#{c}.#{d}"
112
+ return offset + 4
113
+ end
114
+
115
+ end # class A
116
+
117
+ end # class RR
118
+ end # module DNS
119
+ end # module Net
120
+
121
+
@@ -0,0 +1,92 @@
1
+ ##
2
+ #
3
+ # Net::DNS::RR::AAAA
4
+ #
5
+ # $id$
6
+ #
7
+ ##
8
+
9
+ require 'ipaddr'
10
+
11
+ module Net
12
+ module DNS
13
+
14
+ class RR
15
+
16
+ #
17
+ # RR type AAAA
18
+ #
19
+ class AAAA < RR
20
+ attr_reader :address
21
+
22
+ # Assign to the RR::AAAA object a new IPv6 address, which can be in the
23
+ # form of a string or an IPAddr object
24
+ #
25
+ # a.address = "::1"
26
+ # a.address = IPAddr.new("::1")
27
+ #
28
+ def address=(addr)
29
+ @address = check_address addr
30
+ build_pack
31
+ end # address=
32
+
33
+ private
34
+
35
+ def check_address(addr)
36
+ address = ""
37
+ case addr
38
+ when String
39
+ address = IPAddr.new addr
40
+ when IPAddr
41
+ address = addr
42
+ else
43
+ raise RRArgumentError, "Unknown address type: #{addr.inspect}"
44
+ end
45
+ raise RRArgumentError, "Must specify an IPv6 address" unless address.ipv6?
46
+ address
47
+ rescue ArgumentError
48
+ raise RRArgumentError, "Invalid address #{addr.inspect}"
49
+ end
50
+
51
+ def build_pack
52
+ @address_pack = @address.hton
53
+ @rdlength = @address_pack.size
54
+ end
55
+
56
+ def set_type
57
+ @type = Net::DNS::RR::Types.new("AAAA")
58
+ end
59
+
60
+ def get_data
61
+ @address_pack
62
+ end
63
+
64
+ def get_inspect
65
+ "#@address"
66
+ end
67
+
68
+ def subclass_new_from_hash(args)
69
+ if args.has_key? :address
70
+ @address = check_address args[:address]
71
+ else
72
+ raise RRArgumentError, ":address field is mandatory but missing"
73
+ end
74
+ end
75
+
76
+ def subclass_new_from_string(str)
77
+ @address = check_address(str)
78
+ end
79
+
80
+ def subclass_new_from_binary(data,offset)
81
+ arr = data.unpack("@#{offset} n8")
82
+ @address = IPAddr.new sprintf("%x:%x:%x:%x:%x:%x:%x:%x",*arr)
83
+ return offset + 16
84
+ end
85
+
86
+ end # class AAAA
87
+
88
+ end # class RR
89
+ end # module DNS
90
+ end # module Net
91
+
92
+
@@ -0,0 +1,148 @@
1
+ module Net # :nodoc:
2
+ module DNS
3
+
4
+ class RR
5
+
6
+ #
7
+ # This is an auxiliary class to hadle RR class field in a DNS packet.
8
+ #
9
+ class Classes
10
+
11
+ # An 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
+ }
20
+
21
+ # The default value when class is nil in Resource Records
22
+ @@default = Classes["IN"]
23
+
24
+ # Be able to control the default class to assign when
25
+ # cls argument is +nil+. Default to +IN+
26
+ def self.default=(str)
27
+ if Classes.has_key? str
28
+ @@default = Classes[str]
29
+ else
30
+ raise ClassArgumentError, "Unknown class #{str}"
31
+ end
32
+ end
33
+
34
+ # Checks whether +cls+ is a valid RR class.
35
+ def self.valid?(cls)
36
+ case cls
37
+ when String
38
+ return Classes.has_key?(cls)
39
+ when Fixnum
40
+ return Classes.invert.has_key?(cls)
41
+ else
42
+ raise ClassArgumentError, "Wrong cls class: #{cls.class}"
43
+ end
44
+ end
45
+
46
+ # Returns the class in string format, as "IN" or "CH",
47
+ # given the numeric value
48
+ def self.to_str(cls)
49
+ case cls
50
+ when Fixnum
51
+ if Classes.invert.has_key? cls
52
+ return Classes.invert[cls]
53
+ else
54
+ raise ClassArgumentError, "Unknown class number #{cls}"
55
+ end
56
+ else
57
+ raise ClassArgumentError, "Wrong cls class: #{cls.class}"
58
+ end
59
+ end
60
+
61
+ # Gives in output the keys from the +Classes+ hash
62
+ # in a format suited for regexps
63
+ def self.regexp
64
+ Classes.keys.join("|")
65
+ end
66
+
67
+ # Creates a new object representing an RR class. Performs some
68
+ # checks on the argument validity too. Il +cls+ is +nil+, the
69
+ # default value is +ANY+ or the one set with Classes.default=
70
+ def initialize(cls)
71
+ case cls
72
+ when String
73
+ # type in the form "A" or "NS"
74
+ new_from_string(cls.upcase)
75
+ when Fixnum
76
+ # type in numeric form
77
+ new_from_num(cls)
78
+ when nil
79
+ # default type, control with Classes.default=
80
+ @str = Classes.invert[@@default]
81
+ @num = @@default
82
+ else
83
+ raise ClassArgumentError, "Wrong cls class: #{cls.class}"
84
+ end
85
+ end
86
+
87
+ # Constructor for string data class,
88
+ # *PRIVATE* method
89
+ def new_from_string(cls)
90
+ case cls
91
+ when /^CLASS\\d+/
92
+ # TODO!!!
93
+ else
94
+ # String with name of class
95
+ if Classes.has_key? cls
96
+ @str = cls
97
+ @num = Classes[cls]
98
+ else
99
+ raise ClassesArgumentError, "Unknown cls #{cls}"
100
+ end
101
+ end
102
+ end
103
+
104
+ # Contructor for numeric data class
105
+ # *PRIVATE* method
106
+ def new_from_num(cls)
107
+ if Classes.invert.has_key? cls
108
+ @num = cls
109
+ @str = Classes.invert[cls]
110
+ else
111
+ raise ClassesArgumentError, "Unkown cls number #{cls}"
112
+ end
113
+ end
114
+
115
+ # Returns the class in number format
116
+ # (default for normal use)
117
+ def inspect
118
+ @num
119
+ end
120
+
121
+ # Returns the class in string format,
122
+ # i.d. "IN" or "CH" or such a string.
123
+ def to_s
124
+ @str
125
+ end
126
+
127
+ # Returns the class in numeric format,
128
+ # usable by the pack methods for data transfers
129
+ def to_i
130
+ @num.to_i
131
+ end
132
+
133
+
134
+ # Should be used only for testing purpouses
135
+ def to_str
136
+ @num.to_s
137
+ end
138
+
139
+ private :new_from_num, :new_from_string
140
+
141
+ end # class Classes
142
+
143
+ end # class RR
144
+ end # module DNS
145
+ end # module Net
146
+
147
+ class ClassArgumentError < ArgumentError # :nodoc:
148
+ end
@@ -0,0 +1,69 @@
1
+ ##
2
+ #
3
+ # Net::DNS::RR::CNAME
4
+ #
5
+ # $Id: CNAME.rb,v 1.7 2006/07/28 07:33:36 bluemonk Exp $
6
+ #
7
+ ##
8
+
9
+ module Net
10
+ module DNS
11
+
12
+ class RR
13
+
14
+ #------------------------------------------------------------
15
+ # RR type CNAME
16
+ #------------------------------------------------------------
17
+ class CNAME < RR
18
+ attr_reader :cname
19
+
20
+ private
21
+
22
+ def check_name(name)
23
+ unless name =~ /(\w\.?)+\s*$/ and name =~ /[a-zA-Z]/
24
+ raise RRArgumentError, "Canonical Name not valid: #{name}"
25
+ end
26
+ name
27
+ end
28
+
29
+ def build_pack
30
+ @cname_pack = pack_name(@cname)
31
+ @rdlength = @cname_pack.size
32
+ end
33
+
34
+ def set_type
35
+ @type = Net::DNS::RR::Types.new("CNAME")
36
+ end
37
+
38
+ def get_data
39
+ @cname_pack
40
+ end
41
+
42
+ def get_inspect
43
+ "#@cname"
44
+ end
45
+
46
+ def subclass_new_from_hash(args)
47
+ if args.has_key? :cname
48
+ @cname = check_name args[:cname]
49
+ else
50
+ raise RRArgumentError, ":cname field is mandatory but missing"
51
+ end
52
+ end
53
+
54
+ def subclass_new_from_string(str)
55
+ @cname = check_name(str)
56
+ end
57
+
58
+ def subclass_new_from_binary(data,offset)
59
+ @cname,offset = dn_expand(data,offset)
60
+ return offset
61
+ end
62
+
63
+ end # class CNAME
64
+
65
+ end # class RR
66
+ end # module DNS
67
+ end # module Net
68
+
69
+
@@ -0,0 +1,74 @@
1
+ ##
2
+ #
3
+ # Net::DNS::RR::HINFO
4
+ #
5
+ # $Id: HINFO.rb,v 1.4 2006/07/28 07:33:36 bluemonk Exp $
6
+ #
7
+ ##
8
+
9
+ module Net
10
+ module DNS
11
+ class RR
12
+
13
+ #------------------------------------------------------------
14
+ # RR type HINFO
15
+ #------------------------------------------------------------
16
+ class HINFO < RR
17
+ attr_reader :cpu, :os
18
+
19
+ private
20
+
21
+ def check_hinfo(str)
22
+ if str.strip =~ /^["'](.*?)["']\s+["'](.*?)["']$/
23
+ return $1,$2
24
+ else
25
+ raise RRArgumentError, "HINFO section not valid: #{str.inspect}"
26
+ end
27
+ end
28
+
29
+ def build_pack
30
+ @hinfo_pack = [@cpu.size].pack("C") + @cpu
31
+ @hinfo_pack += [@os.size].pack("C") + @os
32
+ @rdlength = @hinfo_pack.size
33
+ end
34
+
35
+ def set_type
36
+ @type = Net::DNS::RR::Types.new("HINFO")
37
+ end
38
+
39
+ def get_data
40
+ @hinfo_pack
41
+ end
42
+
43
+ def get_inspect
44
+ "#@cpu #@os"
45
+ end
46
+
47
+ def subclass_new_from_hash(args)
48
+ if args.has_key? :cpu and args.has_key? :os
49
+ @cpu = args[:cpu]
50
+ @os = args[:os]
51
+ else
52
+ raise RRArgumentError, ":cpu and :os fields are mandatory but missing"
53
+ end
54
+ end
55
+
56
+ def subclass_new_from_string(str)
57
+ @cpu,@os = check_hinfo(str)
58
+ end
59
+
60
+ def subclass_new_from_binary(data,offset)
61
+ len = data.unpack("@#{offset} C")[0]
62
+ @cpu = data[offset+1..offset+1+len]
63
+ offset += len+1
64
+ len = @data.unpack("@#{offset} C")[0]
65
+ @os = data[offset+1..offset+1+len]
66
+ return offset += len+1
67
+ end
68
+
69
+ end # class HINFO
70
+
71
+ end # class RR
72
+ end # module DNS
73
+ end # module Net
74
+
@@ -0,0 +1,68 @@
1
+ ##
2
+ #
3
+ # Net::DNS::RR::MR
4
+ #
5
+ # $Id: MR.rb,v 1.4 2006/07/28 07:33:36 bluemonk Exp $
6
+ #
7
+ ##
8
+
9
+ module Net
10
+ module DNS
11
+
12
+ class RR
13
+
14
+ #------------------------------------------------------------
15
+ # RR type MR
16
+ #------------------------------------------------------------
17
+ class MR < RR
18
+ attr_reader :newname
19
+
20
+ private
21
+
22
+ def check_name(name)
23
+ unless name =~ /(\w\.?)+\s*$/
24
+ raise RRArgumentError, "Name not valid: #{name.inspect}"
25
+ end
26
+ name
27
+ end
28
+
29
+ def build_pack
30
+ @newname_pack = pack_name(@newname)
31
+ @rdlength = @newname_pack.size
32
+ end
33
+
34
+ def set_type
35
+ @type = Net::DNS::RR::Types.new("MR")
36
+ end
37
+
38
+ def get_data
39
+ @newname_pack
40
+ end
41
+
42
+ def get_inspect
43
+ "#@newname"
44
+ end
45
+
46
+ def subclass_new_from_hash(args)
47
+ if args.has_key? :newname
48
+ @newname = check_name args[:newname]
49
+ else
50
+ raise RRArgumentError, ":newname field is mandatory but missing"
51
+ end
52
+ end
53
+
54
+ def subclass_new_from_string(str)
55
+ @newname = check_name(str)
56
+ end
57
+
58
+ def subclass_new_from_array(data,offset)
59
+ @newname = dn_expand(data,offset)
60
+ return offset
61
+ end
62
+
63
+ end # class MR
64
+
65
+ end # class RR
66
+ end # module DNS
67
+ end # module Net
68
+
@@ -0,0 +1,74 @@
1
+ ##
2
+ #
3
+ # Net::DNS::RR::MX
4
+ #
5
+ # $Id: MX.rb,v 1.8 2006/07/28 07:33:36 bluemonk Exp $
6
+ #
7
+ ##
8
+
9
+
10
+ module Net
11
+ module DNS
12
+ class RR
13
+
14
+ #------------------------------------------------------------
15
+ # RR type MX
16
+ #------------------------------------------------------------
17
+ class MX < RR
18
+ attr_reader :preference, :exchange
19
+
20
+ private
21
+
22
+ def check_mx(str)
23
+ if str.strip =~ /^(\d+)\s+(\S+)$/
24
+ return $1.to_i,$2
25
+ else
26
+ raise RRArgumentError, "MX section not valid"
27
+ end
28
+ end
29
+
30
+ def build_pack
31
+ @mx_pack = [@preference].pack("n") + pack_name(@exchange)
32
+ @rdlength = @mx_pack.size
33
+ end
34
+
35
+ def set_type
36
+ @type = Net::DNS::RR::Types.new("MX")
37
+ end
38
+
39
+ def get_data
40
+ @mx_pack
41
+ end
42
+
43
+ def get_inspect
44
+ "#@preference #@exchange"
45
+ end
46
+
47
+ def subclass_new_from_hash(args)
48
+ if args.has_key? :preference and args.has_key? :exchange
49
+ @preference = args[0][:preference].to_i
50
+ @exchange = args[0][:exchange]
51
+ else
52
+ raise RRArgumentError, ":preference and :exchange fields are mandatory but missing"
53
+ end
54
+ end
55
+
56
+ def subclass_new_from_string(str)
57
+ @preference,@exchange = check_mx(str)
58
+ end
59
+
60
+ def subclass_new_from_binary(data,offset)
61
+ @preference = data.unpack("@#{offset} n")[0]
62
+ offset += 2
63
+ @exchange,offset = dn_expand(data,offset)
64
+ return offset
65
+ end
66
+
67
+ end # class MX
68
+
69
+ end # class RR
70
+ end # module DNS
71
+ end # module Net
72
+
73
+
74
+
@@ -0,0 +1,70 @@
1
+ ##
2
+ #
3
+ # Net::DNS::RR::NS
4
+ #
5
+ # $Id: NS.rb,v 1.8 2006/07/28 07:33:36 bluemonk Exp $
6
+ #
7
+ ##
8
+
9
+ module Net
10
+ module DNS
11
+
12
+ class RR
13
+
14
+ #------------------------------------------------------------
15
+ # RR type NS
16
+ #------------------------------------------------------------
17
+ class NS < RR
18
+ attr_reader :nsdname
19
+
20
+ private
21
+
22
+ def check_name(name)
23
+ unless name =~ /(\w\.?)+\s*$/ and name =~ /[a-zA-Z]/
24
+ raise RRArgumentError, "NS Domain Name not valid: #{name}"
25
+ end
26
+ name
27
+ end
28
+
29
+ def build_pack
30
+ @nsdname_pack = pack_name(@nsdname)
31
+ @rdlength = @nsdname_pack.size
32
+ end
33
+
34
+ def set_type
35
+ @type = Net::DNS::RR::Types.new("NS")
36
+ end
37
+
38
+ def get_data
39
+ @nsdname_pack
40
+ end
41
+
42
+ def get_inspect
43
+ "#@nsdname"
44
+ end
45
+
46
+ def subclass_new_from_hash(args)
47
+ if args.has_key? :nsdname
48
+ @nsdname = check_name args[:nsdname]
49
+ else
50
+ raise RRArgumentError, ":nsdname field is mandatory but missing"
51
+ end
52
+ end
53
+
54
+ def subclass_new_from_string(str)
55
+ @nsdname = check_name(str)
56
+ end
57
+
58
+ def subclass_new_from_binary(data,offset)
59
+ @nsdname,offset = dn_expand(data,offset)
60
+ return offset
61
+ end
62
+
63
+ end # class NS
64
+
65
+ end # class RR
66
+ end # module DNS
67
+ end # module Net
68
+
69
+
70
+