dnsruby 1.55 → 1.56.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +96 -0
  3. data/Rakefile +30 -29
  4. data/demo/axfr.rb +93 -93
  5. data/demo/check_soa.rb +99 -99
  6. data/demo/check_zone.rb +59 -59
  7. data/demo/digdlv.rb +43 -43
  8. data/demo/digroot.rb +34 -34
  9. data/demo/example_recurse.rb +14 -14
  10. data/demo/mresolv.rb +30 -30
  11. data/demo/mx.rb +31 -31
  12. data/demo/rubydig.rb +37 -37
  13. data/demo/to_resolve.txt +3088 -3088
  14. data/demo/trace_dns.rb +46 -46
  15. data/lib/dnsruby.rb +161 -526
  16. data/lib/dnsruby/DNS.rb +305 -0
  17. data/lib/{Dnsruby/Cache.rb → dnsruby/cache.rb} +152 -152
  18. data/lib/{Dnsruby → dnsruby}/code_mapper.rb +48 -52
  19. data/lib/dnsruby/code_mappers.rb +295 -0
  20. data/lib/{Dnsruby/Config.rb → dnsruby/config.rb} +454 -454
  21. data/lib/{Dnsruby → dnsruby}/dnssec.rb +91 -91
  22. data/lib/{Dnsruby/Hosts.rb → dnsruby/hosts.rb} +125 -125
  23. data/lib/{Dnsruby → dnsruby}/ipv4.rb +26 -26
  24. data/lib/{Dnsruby → dnsruby}/ipv6.rb +42 -42
  25. data/lib/{Dnsruby → dnsruby}/key_cache.rb +29 -29
  26. data/lib/dnsruby/message/decoder.rb +164 -0
  27. data/lib/dnsruby/message/encoder.rb +75 -0
  28. data/lib/dnsruby/message/header.rb +249 -0
  29. data/lib/dnsruby/message/message.rb +629 -0
  30. data/lib/dnsruby/message/question.rb +86 -0
  31. data/lib/dnsruby/message/section.rb +96 -0
  32. data/lib/{Dnsruby → dnsruby}/name.rb +141 -141
  33. data/lib/dnsruby/packet_sender.rb +661 -0
  34. data/lib/{Dnsruby/Recursor.rb → dnsruby/recursor.rb} +235 -233
  35. data/lib/dnsruby/resolv.rb +113 -0
  36. data/lib/dnsruby/resolver.rb +1192 -0
  37. data/lib/dnsruby/resource/A.rb +56 -0
  38. data/lib/dnsruby/resource/AAAA.rb +54 -0
  39. data/lib/{Dnsruby → dnsruby}/resource/AFSDB.rb +68 -68
  40. data/lib/{Dnsruby → dnsruby}/resource/CERT.rb +105 -105
  41. data/lib/{Dnsruby → dnsruby}/resource/DHCID.rb +54 -54
  42. data/lib/dnsruby/resource/DLV.rb +27 -0
  43. data/lib/{Dnsruby → dnsruby}/resource/DNSKEY.rb +372 -372
  44. data/lib/{Dnsruby → dnsruby}/resource/DS.rb +255 -255
  45. data/lib/{Dnsruby → dnsruby}/resource/HINFO.rb +71 -71
  46. data/lib/{Dnsruby → dnsruby}/resource/HIP.rb +29 -29
  47. data/lib/{Dnsruby → dnsruby}/resource/IN.rb +30 -30
  48. data/lib/{Dnsruby → dnsruby}/resource/IPSECKEY.rb +31 -31
  49. data/lib/{Dnsruby → dnsruby}/resource/ISDN.rb +62 -62
  50. data/lib/{Dnsruby → dnsruby}/resource/KX.rb +65 -65
  51. data/lib/{Dnsruby → dnsruby}/resource/LOC.rb +263 -263
  52. data/lib/{Dnsruby → dnsruby}/resource/MINFO.rb +69 -69
  53. data/lib/{Dnsruby → dnsruby}/resource/MX.rb +65 -65
  54. data/lib/{Dnsruby → dnsruby}/resource/NAPTR.rb +98 -98
  55. data/lib/{Dnsruby → dnsruby}/resource/NSAP.rb +171 -171
  56. data/lib/dnsruby/resource/NSEC.rb +275 -0
  57. data/lib/dnsruby/resource/NSEC3.rb +332 -0
  58. data/lib/dnsruby/resource/NSEC3PARAM.rb +135 -0
  59. data/lib/dnsruby/resource/OPT.rb +272 -0
  60. data/lib/{Dnsruby → dnsruby}/resource/PX.rb +70 -70
  61. data/lib/{Dnsruby → dnsruby}/resource/RP.rb +75 -75
  62. data/lib/dnsruby/resource/RR.rb +421 -0
  63. data/lib/dnsruby/resource/RRSIG.rb +275 -0
  64. data/lib/dnsruby/resource/RRSet.rb +190 -0
  65. data/lib/{Dnsruby → dnsruby}/resource/RT.rb +67 -67
  66. data/lib/{Dnsruby → dnsruby}/resource/SOA.rb +94 -94
  67. data/lib/dnsruby/resource/SPF.rb +29 -0
  68. data/lib/dnsruby/resource/SRV.rb +112 -0
  69. data/lib/{Dnsruby → dnsruby}/resource/SSHFP.rb +14 -14
  70. data/lib/dnsruby/resource/TKEY.rb +163 -0
  71. data/lib/dnsruby/resource/TSIG.rb +593 -0
  72. data/lib/{Dnsruby → dnsruby}/resource/TXT.rb +191 -191
  73. data/lib/dnsruby/resource/X25.rb +55 -0
  74. data/lib/{Dnsruby → dnsruby}/resource/domain_name.rb +25 -25
  75. data/lib/{Dnsruby → dnsruby}/resource/generic.rb +80 -80
  76. data/lib/dnsruby/resource/resource.rb +25 -0
  77. data/lib/{Dnsruby → dnsruby}/select_thread.rb +148 -148
  78. data/lib/{Dnsruby/SingleResolver.rb → dnsruby/single_resolver.rb} +60 -60
  79. data/lib/{Dnsruby → dnsruby}/single_verifier.rb +344 -344
  80. data/lib/dnsruby/the_log.rb +44 -0
  81. data/lib/dnsruby/update.rb +278 -0
  82. data/lib/dnsruby/validator_thread.rb +124 -0
  83. data/lib/dnsruby/version.rb +3 -0
  84. data/lib/{Dnsruby → dnsruby}/zone_reader.rb +93 -93
  85. data/lib/{Dnsruby → dnsruby}/zone_transfer.rb +377 -377
  86. data/test/spec_helper.rb +16 -0
  87. data/test/tc_axfr.rb +31 -34
  88. data/test/tc_cache.rb +32 -32
  89. data/test/tc_dlv.rb +28 -28
  90. data/test/tc_dns.rb +73 -76
  91. data/test/tc_dnskey.rb +31 -32
  92. data/test/tc_dnsruby.rb +50 -44
  93. data/test/tc_ds.rb +36 -36
  94. data/test/tc_escapedchars.rb +252 -255
  95. data/test/tc_hash.rb +17 -21
  96. data/test/tc_header.rb +48 -57
  97. data/test/tc_hip.rb +19 -22
  98. data/test/tc_ipseckey.rb +18 -21
  99. data/test/tc_keith.rb +300 -0
  100. data/test/tc_message.rb +87 -0
  101. data/test/tc_misc.rb +83 -87
  102. data/test/tc_name.rb +81 -84
  103. data/test/tc_naptr.rb +18 -21
  104. data/test/tc_nsec.rb +55 -55
  105. data/test/tc_nsec3.rb +23 -24
  106. data/test/tc_nsec3param.rb +20 -21
  107. data/test/tc_packet.rb +90 -93
  108. data/test/tc_packet_unique_push.rb +48 -51
  109. data/test/tc_question.rb +30 -33
  110. data/test/tc_queue.rb +16 -17
  111. data/test/tc_recur.rb +16 -17
  112. data/test/tc_res_config.rb +38 -41
  113. data/test/tc_res_env.rb +29 -32
  114. data/test/tc_res_file.rb +26 -29
  115. data/test/tc_res_opt.rb +62 -65
  116. data/test/tc_resolver.rb +287 -242
  117. data/test/tc_rr-opt.rb +70 -63
  118. data/test/tc_rr-txt.rb +68 -71
  119. data/test/tc_rr-unknown.rb +45 -48
  120. data/test/tc_rr.rb +76 -70
  121. data/test/tc_rrset.rb +21 -22
  122. data/test/tc_rrsig.rb +19 -20
  123. data/test/tc_single_resolver.rb +294 -297
  124. data/test/tc_soak.rb +199 -202
  125. data/test/tc_soak_base.rb +29 -34
  126. data/test/tc_sshfp.rb +20 -23
  127. data/test/tc_tcp.rb +32 -35
  128. data/test/tc_tkey.rb +41 -44
  129. data/test/tc_tsig.rb +81 -84
  130. data/test/tc_update.rb +108 -111
  131. data/test/tc_validator.rb +29 -29
  132. data/test/tc_verifier.rb +81 -82
  133. data/test/ts_dnsruby.rb +16 -15
  134. data/test/ts_offline.rb +62 -63
  135. data/test/ts_online.rb +115 -115
  136. metadata +155 -90
  137. data/README +0 -59
  138. data/lib/Dnsruby/DNS.rb +0 -305
  139. data/lib/Dnsruby/PacketSender.rb +0 -656
  140. data/lib/Dnsruby/Resolver.rb +0 -1189
  141. data/lib/Dnsruby/TheLog.rb +0 -44
  142. data/lib/Dnsruby/message.rb +0 -1230
  143. data/lib/Dnsruby/resource/A.rb +0 -56
  144. data/lib/Dnsruby/resource/AAAA.rb +0 -54
  145. data/lib/Dnsruby/resource/DLV.rb +0 -27
  146. data/lib/Dnsruby/resource/NSEC.rb +0 -298
  147. data/lib/Dnsruby/resource/NSEC3.rb +0 -340
  148. data/lib/Dnsruby/resource/NSEC3PARAM.rb +0 -135
  149. data/lib/Dnsruby/resource/OPT.rb +0 -213
  150. data/lib/Dnsruby/resource/RRSIG.rb +0 -275
  151. data/lib/Dnsruby/resource/SPF.rb +0 -29
  152. data/lib/Dnsruby/resource/SRV.rb +0 -112
  153. data/lib/Dnsruby/resource/TKEY.rb +0 -163
  154. data/lib/Dnsruby/resource/TSIG.rb +0 -593
  155. data/lib/Dnsruby/resource/X25.rb +0 -55
  156. data/lib/Dnsruby/resource/resource.rb +0 -678
  157. data/lib/Dnsruby/update.rb +0 -278
  158. data/lib/Dnsruby/validator_thread.rb +0 -124
@@ -1,29 +0,0 @@
1
- #--
2
- #Copyright 2007 Nominet UK
3
- #
4
- #Licensed under the Apache License, Version 2.0 (the "License");
5
- #you may not use this file except in compliance with the License.
6
- #You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- #Unless required by applicable law or agreed to in writing, software
11
- #distributed under the License is distributed on an "AS IS" BASIS,
12
- #WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- #See the License for the specific language governing permissions and
14
- #limitations under the License.
15
- #++
16
- module Dnsruby
17
- class RR
18
- #DNS SPF resource record
19
-
20
- #This is a clone of the TXT record. This class therfore completely inherits
21
- #all properties of the Dnsruby::Resource::TXT class.
22
- #
23
- #Please see the Dnsruby::Resource::TXT documentation for details
24
- #RFC 1035 Section 3.3.14, draft-schlitt-ospf-classic-02.txt
25
- class SPF < TXT
26
- TypeValue = Types::SPF #:nodoc: all
27
- end
28
- end
29
- end
@@ -1,112 +0,0 @@
1
- #--
2
- #Copyright 2007 Nominet UK
3
- #
4
- #Licensed under the Apache License, Version 2.0 (the "License");
5
- #you may not use this file except in compliance with the License.
6
- #You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- #Unless required by applicable law or agreed to in writing, software
11
- #distributed under the License is distributed on an "AS IS" BASIS,
12
- #WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- #See the License for the specific language governing permissions and
14
- #limitations under the License.
15
- #++
16
- module Dnsruby
17
- class RR
18
- module IN
19
- # SRV resource record defined in RFC 2782
20
- #
21
- # These records identify the hostname and port that a service is
22
- # available at.
23
- #
24
- # The format is:
25
- # _Service._Proto.Name TTL Class SRV Priority Weight Port Target
26
- #
27
- # The fields specific to SRV are defined in RFC 2782
28
- class SRV < RR
29
- ClassHash[[TypeValue = Types::SRV, ClassValue = ClassValue]] = self #:nodoc: all
30
-
31
- # The priority of this target host.
32
- # A client MUST attempt
33
- # to contact the target host with the lowest-numbered priority it can
34
- # reach; target hosts with the same priority SHOULD be tried in an
35
- # order defined by the weight field. The range is 0-65535. Note that
36
- # it is not widely implemented and should be set to zero.
37
- attr_accessor :priority
38
-
39
- # A server selection mechanism.
40
- # The weight field specifies
41
- # a relative weight for entries with the same priority. Larger weights
42
- # SHOULD be given a proportionately higher probability of being
43
- # selected. The range of this number is 0-65535. Domain administrators
44
- # SHOULD use Weight 0 when there isn't any server selection to do, to
45
- # make the RR easier to read for humans (less noisy). Note that it is
46
- # not widely implemented and should be set to zero.
47
- attr_accessor :weight
48
-
49
- # The port on this target host of this service. The range is 0-65535.
50
- attr_accessor :port
51
-
52
- # The domain name of the target host. A target of "." means
53
- # that the service is decidedly not available at this domain.
54
- attr_accessor :target
55
-
56
- def from_data(data) #:nodoc: all
57
- @priority, @weight, @port, @target = data
58
- end
59
-
60
- def from_hash(hash)
61
- if hash[:priority]
62
- @priority = hash[:priority].to_i
63
- end
64
- if hash[:weight]
65
- @weight = hash[:weight].to_i
66
- end
67
- if hash[:port]
68
- @port = hash[:port].to_i
69
- end
70
- if hash[:target]
71
- @target= Name.create(hash[:target])
72
- end
73
- end
74
-
75
- def from_string(input)
76
- if (input.length > 0)
77
- names = input.split(" ")
78
- @priority = names[0].to_i
79
- @weight = names[1].to_i
80
- @port = names[2].to_i
81
- if (names[3])
82
- @target = Name.create(names[3])
83
- end
84
- end
85
- end
86
-
87
- def rdata_to_string
88
- if (@target!=nil)
89
- return "#{@priority} #{@weight} #{@port} #{@target.to_s(true)}"
90
- else
91
- return ""
92
- end
93
- end
94
-
95
- def encode_rdata(msg, canonical=false) #:nodoc: all
96
- msg.put_pack("n", @priority)
97
- msg.put_pack("n", @weight)
98
- msg.put_pack("n", @port)
99
- msg.put_name(@target,canonical)
100
- end
101
-
102
- def self.decode_rdata(msg) #:nodoc: all
103
- priority, = msg.get_unpack("n")
104
- weight, = msg.get_unpack("n")
105
- port, = msg.get_unpack("n")
106
- target = msg.get_name
107
- return self.new([priority, weight, port, target])
108
- end
109
- end
110
- end
111
- end
112
- end
@@ -1,163 +0,0 @@
1
- #--
2
- #Copyright 2007 Nominet UK
3
- #
4
- #Licensed under the Apache License, Version 2.0 (the "License");
5
- #you may not use this file except in compliance with the License.
6
- #You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- #Unless required by applicable law or agreed to in writing, software
11
- #distributed under the License is distributed on an "AS IS" BASIS,
12
- #WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- #See the License for the specific language governing permissions and
14
- #limitations under the License.
15
- #++
16
- module Dnsruby
17
-
18
- class Modes < CodeMapper
19
- # The key is assigned by the server (unimplemented)
20
- SERVERASSIGNED = 1
21
-
22
- # The key is computed using a Diffie-Hellman key exchange
23
- DIFFIEHELLMAN = 2
24
-
25
- # The key is computed using GSS_API (unimplemented)
26
- GSSAPI = 3
27
-
28
- # The key is assigned by the resolver (unimplemented)
29
- RESOLVERASSIGNED = 4
30
-
31
- # The key should be deleted
32
- DELETE = 5
33
- update()
34
- end
35
-
36
- class RR
37
- #RFC2930
38
- class TKEY < RR
39
- TypeValue = Types::TKEY #:nodoc: all
40
- ClassValue = nil #:nodoc: all
41
- ClassHash[[TypeValue, Classes::ANY]] = self #:nodoc: all
42
-
43
- attr_reader :key_size
44
- attr_accessor :key
45
- #Gets or sets the domain name that specifies the name of the algorithm.
46
- #The default algorithm is gss.microsoft.com
47
- #
48
- # rr.algorithm=(algorithm_name)
49
- # print "algorithm = ", rr.algorithm, "\n"
50
- #
51
- attr_accessor :algorithm
52
- #Gets or sets the inception time as the number of seconds since 1 Jan 1970
53
- #00:00:00 UTC.
54
- #
55
- #The default inception time is the current time.
56
- #
57
- # rr.inception=(time)
58
- # print "inception = ", rr.inception, "\n"
59
- #
60
- attr_accessor :inception
61
- #Gets or sets the expiration time as the number of seconds since 1 Jan 1970
62
- #00:00:00 UTC.
63
- #
64
- #The default expiration time is the current time plus 1 day.
65
- #
66
- # rr.expiration=(time)
67
- # print "expiration = ", rr.expiration, "\n"
68
- #
69
- attr_accessor :expiration
70
- #Sets the key mode (see rfc2930). The default is 3 which corresponds to GSSAPI
71
- #
72
- # rr.mode=(3)
73
- # print "mode = ", rr.mode, "\n"
74
- #
75
- attr_accessor :mode
76
- #Returns the RCODE covering TKEY processing. See RFC 2930 for details.
77
- #
78
- # print "error = ", rr.error, "\n"
79
- #
80
- attr_accessor :error
81
- #Returns the length of the Other Data. Should be zero.
82
- #
83
- # print "other size = ", rr.other_size, "\n"
84
- #
85
- attr_reader :other_size
86
- #Returns the Other Data. This field should be empty.
87
- #
88
- # print "other data = ", rr.other_data, "\n"
89
- #
90
- attr_reader :other_data
91
-
92
- def other_data=(od)
93
- @other_data=od
94
- @other_size=@other_data.length
95
- end
96
-
97
- def initialize
98
- @algorithm = "gss.microsoft.com"
99
- @inception = Time.now
100
- @expiration = Time.now + 24*60*60
101
- @mode = Modes.GSSAPI
102
- @error = 0
103
- @other_size = 0
104
- @other_data = ""
105
-
106
- # RFC 2845 Section 2.3
107
- @klass = Classes.ANY
108
- # RFC 2845 Section 2.3
109
- @ttl = 0
110
- end
111
-
112
- def from_hash(hash)
113
- super(hash)
114
- if (algorithm)
115
- @algorithm = Name.create(hash[:algorithm])
116
- end
117
- end
118
-
119
- def from_data(data) #:nodoc: all
120
- @algorithm, @inception, @expiration, @mode, @error, @key_size, @key, @other_size, @other_data = data
121
- end
122
-
123
- # Create the RR from a standard string
124
- def from_string(string) #:nodoc: all
125
- Dnsruby.log.error("Dnsruby::RR::TKEY#from_string called, but no text format defined for TKEY")
126
- end
127
-
128
- def rdata_to_string
129
- rdatastr=""
130
-
131
- if (@algorithm!=nil)
132
- error = @error
133
- error = "UNDEFINED" unless error!=nil
134
- rdatastr = "#{@algorithm.to_s(true)} #{error}"
135
- if (@other_size != nil && @other_size >0 && @other_data!=nil)
136
- rdatastr += " #{@other_data}"
137
- end
138
- end
139
-
140
- return rdatastr
141
- end
142
-
143
- def encode_rdata(msg, canonical=false) #:nodoc: all
144
- msg.put_name(@algorithm, canonical)
145
- msg.put_pack("NNnn", @inception, @expiration, @mode, @error)
146
- msg.put_pack("n", @key.length)
147
- msg.put_bytes(@key)
148
- msg.put_pack("n", @other_data.length)
149
- msg.put_bytes(@other_data)
150
- end
151
-
152
- def self.decode_rdata(msg) #:nodoc: all
153
- alg=msg.get_name
154
- inc, exp, mode, error = msg.get_unpack("NNnn")
155
- key_size, =msg.get_unpack("n")
156
- key=msg.get_bytes(key_size)
157
- other_size, =msg.get_unpack("n")
158
- other=msg.get_bytes(other_size)
159
- return self.new([alg, inc, exp, mode, error, key_size, key, other_size, other])
160
- end
161
- end
162
- end
163
- end
@@ -1,593 +0,0 @@
1
- #--
2
- #Copyright 2007 Nominet UK
3
- #
4
- #Licensed under the Apache License, Version 2.0 (the "License");
5
- #you may not use this file except in compliance with the License.
6
- #You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- #Unless required by applicable law or agreed to in writing, software
11
- #distributed under the License is distributed on an "AS IS" BASIS,
12
- #WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- #See the License for the specific language governing permissions and
14
- #limitations under the License.
15
- #++
16
- #require 'base64'
17
- begin
18
- require 'openssl'
19
- rescue LoadError
20
- print "OpenSSL not found - ignoring\n"
21
- end
22
- module Dnsruby
23
- class RR
24
- #TSIG implements RFC2845.
25
- #
26
- #"This protocol allows for transaction level authentication using
27
- #shared secrets and one way hashing. It can be used to authenticate
28
- #dynamic updates as coming from an approved client, or to authenticate
29
- #responses as coming from an approved recursive name server."
30
- #
31
- #A Dnsruby::RR::TSIG can represent the data present in a TSIG RR.
32
- #However, it can also represent the data (specified in RFC2845) used
33
- #to sign or verify a DNS message.
34
- #
35
- #
36
- #Example code :
37
- # res = Dnsruby::Resolver.new("ns0.validation-test-servers.nominet.org.uk")
38
- #
39
- # # Now configure the resolver with the TSIG key for signing/verifying
40
- # KEY_NAME="rubytsig"
41
- # KEY = "8n6gugn4aJ7MazyNlMccGKH1WxD2B3UvN/O/RA6iBupO2/03u9CTa3Ewz3gBWTSBCH3crY4Kk+tigNdeJBAvrw=="
42
- # res.tsig=KEY_NAME, KEY
43
- #
44
- # update = Dnsruby::Update.new("validation-test-servers.nominet.org.uk")
45
- # # Generate update record name, and test it has been made. Then delete it and check it has been deleted
46
- # update_name = generate_update_name
47
- # update.absent(update_name)
48
- # update.add(update_name, 'TXT', 100, "test signed update")
49
- #
50
- # # Resolver will automatically sign message and verify response
51
- # response = res.send_message(update)
52
- # assert(response.verified?) # Check that the response has been verified
53
- class TSIG < RR
54
- HMAC_MD5 = Name.create("HMAC-MD5.SIG-ALG.REG.INT.")
55
- HMAC_SHA1 = Name.create("hmac-sha1.")
56
- HMAC_SHA256 = Name.create("hmac-sha256.")
57
-
58
- DEFAULT_FUDGE = 300
59
-
60
- DEFAULT_ALGORITHM = HMAC_MD5
61
-
62
- #Generates a TSIG record and adds it to the message.
63
- #Takes an optional original_request argument for the case where this is
64
- #a response to a query (RFC2845 3.4.1)
65
- #
66
- #Message#tsigstate will be set to :Signed.
67
- def apply(message, original_request=nil)
68
- if (!message.signed?)
69
- tsig_rr = generate(message, original_request)
70
- message.add_additional(tsig_rr)
71
- message.tsigstate = :Signed
72
- @query = message
73
- tsig_rr.query = message
74
- end
75
- end
76
-
77
- def query=q#:nodoc: all
78
- @query = q
79
- end
80
-
81
-
82
- #Generates a TSIG record
83
- def generate(msg, original_request = nil, data="", msg_bytes=nil, tsig_rr=self)#:nodoc: all
84
- time_signed=@time_signed
85
- if (!time_signed)
86
- time_signed=Time.now.to_i
87
- end
88
- if (tsig_rr.time_signed)
89
- time_signed = tsig_rr.time_signed
90
- end
91
-
92
- if (original_request)
93
- # # Add the request MAC if present (used to validate responses).
94
- # hmac.update(pack("H*", request_mac))
95
- mac_bytes = MessageEncoder.new {|m|
96
- m.put_pack('n', original_request.tsig.mac_size)
97
- m.put_bytes(original_request.tsig.mac)
98
- }.to_s
99
- data += mac_bytes
100
- # Original ID - should we set message ID to original ID?
101
- if (tsig_rr != self)
102
- msg.header.id = tsig_rr.original_id
103
- else
104
- msg.header.id = original_request.header.id
105
- end
106
- end
107
-
108
- if (!msg_bytes)
109
- msg_bytes = msg.encode
110
- data += msg_bytes
111
- else
112
- # If msg_bytes came in, we need somehow to remove the TSIG RR
113
- # It is the last record, so we can strip it if we know where it starts
114
- # We must also poke the header ARcount to decrement it
115
- msg_bytes = Header.decrement_arcount_encoded(msg_bytes)
116
- data += msg_bytes[0, msg.tsigstart]
117
- end
118
-
119
- data += sig_data(tsig_rr, time_signed)
120
-
121
- mac = calculate_mac(tsig_rr.algorithm, data)
122
-
123
- mac_size = mac.length
124
-
125
- new_tsig_rr = Dnsruby::RR.create({
126
- :name => tsig_rr.name,
127
- :type => Types.TSIG,
128
- :ttl => tsig_rr.ttl,
129
- :klass => tsig_rr.klass,
130
- :algorithm => tsig_rr.algorithm,
131
- :fudge => tsig_rr.fudge,
132
- :key => @key,
133
- :mac => mac,
134
- :mac_size => mac_size,
135
- :error => tsig_rr.error,
136
- :time_signed => time_signed,
137
- :original_id => msg.header.id
138
- })
139
- return new_tsig_rr
140
-
141
- end
142
-
143
- def calculate_mac(algorithm, data)
144
- mac=nil
145
- #+ if (key_size > max_digest_len) {
146
- #+ EVP_DigestInit(&ectx, digester);
147
- #+ EVP_DigestUpdate(&ectx, (const void*) key_bytes, key_size);
148
- #+ EVP_DigestFinal(&ectx, key_bytes, NULL);
149
- #+ key_size = max_digest_len;
150
- #+ }
151
- key = @key.gsub(" ", "")
152
- # key = Base64::decode64(key)
153
- key = key.unpack("m*")[0]
154
- if (algorithm.to_s.downcase == HMAC_MD5.to_s.downcase)
155
- mac = OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, key, data)
156
- elsif (algorithm == HMAC_SHA1)
157
- mac = OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new, key, data)
158
- elsif (algorithm == HMAC_SHA256)
159
- mac = OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, key, data)
160
- else
161
- # Should we allow client to pass in their own signing function?
162
- raise VerifyError.new("Algorithm #{algorithm} unsupported by TSIG")
163
- end
164
- return mac
165
- end
166
-
167
- # Private method to return the TSIG RR data to be signed
168
- def sig_data(tsig_rr, time_signed=@time_signed) #:nodoc: all
169
- return MessageEncoder.new { |msg|
170
- msg.put_name(tsig_rr.name.downcase, true)
171
- msg.put_pack('nN', tsig_rr.klass.code, tsig_rr.ttl)
172
- msg.put_name(tsig_rr.algorithm.downcase, true)
173
-
174
- time_high = (time_signed >> 32)
175
- time_low = (time_signed & 0xFFFFFFFF)
176
- msg.put_pack('nN', time_high, time_low)
177
- msg.put_pack('n', tsig_rr.fudge)
178
- msg.put_pack('n', tsig_rr.error)
179
- msg.put_pack('n', tsig_rr.other_size)
180
- msg.put_bytes(tsig_rr.other_data)
181
- }.to_s
182
- end
183
-
184
- #Verify a response. This method will be called by Dnsruby::SingleResolver
185
- #before passing a response to the client code.
186
- #The TSIG record will be removed from packet before passing to client, and
187
- #the Message#tsigstate and Message#tsigerror will be set accordingly.
188
- #Message#tsigstate will be set to one of :
189
- #* :Failed
190
- #* :Verified
191
- def verify(query, response, response_bytes, buf="")
192
- # 4.6. Client processing of answer
193
- #
194
- # When a client receives a response from a server and expects to see a
195
- # TSIG, it first checks if the TSIG RR is present in the response.
196
- # Otherwise, the response is treated as having a format error and
197
- # discarded. The client then extracts the TSIG, adjusts the ARCOUNT,
198
- # and calculates the keyed digest in the same way as the server. If
199
- # the TSIG does not validate, that response MUST be discarded, unless
200
- # the RCODE is 9 (NOTAUTH), in which case the client SHOULD attempt to
201
- # verify the response as if it were a TSIG Error response, as specified
202
- # in [4.3]. A message containing an unsigned TSIG record or a TSIG
203
- # record which fails verification SHOULD not be considered an
204
- # acceptable response; the client SHOULD log an error and continue to
205
- # wait for a signed response until the request times out.
206
-
207
- # So, this verify method should simply remove the TSIG RR and calculate
208
- # the MAC (using original request MAC if required).
209
- # Should set tsigstate on packet appropriately, and return error.
210
- # Side effect is packet is stripped of TSIG.
211
- # Resolver (or client) can then decide what to do...
212
-
213
- msg_tsig_rr = response.tsig
214
- if (!verify_common(response))
215
- return false
216
- end
217
-
218
- new_msg_tsig_rr = generate(response, query, buf, response_bytes, msg_tsig_rr)
219
-
220
- if (msg_tsig_rr.mac == new_msg_tsig_rr.mac)
221
- response.tsigstate = :Verified
222
- response.tsigerror = RCode.NOERROR
223
- return true
224
- else
225
- response.tsigstate = :Failed
226
- response.tsigerror = RCode.BADSIG
227
- return false
228
- end
229
- end
230
-
231
- def verify_common(response)#:nodoc: all
232
- tsig_rr = response.tsig
233
-
234
- if (!tsig_rr)
235
- response.tsigerror = RCode.FORMERR
236
- response.tsigstate = :Failed
237
- return false
238
- end
239
-
240
- response.additional.delete(tsig_rr)
241
- response.header.arcount-=1
242
-
243
- # First, check the TSIG error in the RR
244
- if (tsig_rr.error != RCode.NOERROR)
245
- response.tsigstate = :Failed
246
- response.tsigerror = tsig_rr.error
247
- return false
248
- end
249
-
250
- if ((tsig_rr.name != @name) || (tsig_rr.algorithm.downcase != @algorithm.downcase))
251
- Dnsruby.log.error("BADKEY failure")
252
- response.tsigstate = :Failed
253
- response.tsigerror = RCode.BADKEY
254
- return false
255
- end
256
-
257
- # Check time_signed (RFC2845, 4.5.2) - only really necessary for server
258
- if (Time.now.to_i > tsig_rr.time_signed + tsig_rr.fudge ||
259
- Time.now.to_i < tsig_rr.time_signed - tsig_rr.fudge)
260
- Dnsruby.log.error("TSIG failed with BADTIME")
261
- response.tsigstate = :Failed
262
- response.tsigerror = RCode.BADTIME
263
- return false
264
- end
265
-
266
- return true
267
- end
268
-
269
- #Checks TSIG signatures across sessions of multiple DNS envelopes.
270
- #This method is called each time a new envelope comes in. The envelope
271
- #is checked - if a TSIG is present, them the stream so far is verified,
272
- #and the response#tsigstate set to :Verified. If a TSIG is not present,
273
- #and does not need to be present, then the message is added to the digest
274
- #stream and the response#tsigstate is set to :Intermediate.
275
- #If there is an error with the TSIG verification, then the response#tsigstate
276
- #is set to :Failed.
277
- #Like verify, this method will only be called by the Dnsruby::SingleResolver
278
- #class. Client code need not call this method directly.
279
- def verify_envelope(response, response_bytes)
280
- #RFC2845 Section 4.4
281
- #-----
282
- #A DNS TCP session can include multiple DNS envelopes. This is, for
283
- #example, commonly used by zone transfer. Using TSIG on such a
284
- #connection can protect the connection from hijacking and provide data
285
- #integrity. The TSIG MUST be included on the first and last DNS
286
- #envelopes. It can be optionally placed on any intermediary
287
- #envelopes. It is expensive to include it on every envelopes, but it
288
- #MUST be placed on at least every 100'th envelope. The first envelope
289
- #is processed as a standard answer, and subsequent messages have the
290
- #following digest components:
291
- #
292
- #* Prior Digest (running)
293
- #* DNS Messages (any unsigned messages since the last TSIG)
294
- #* TSIG Timers (current message)
295
- #
296
- #This allows the client to rapidly detect when the session has been
297
- #altered; at which point it can close the connection and retry. If a
298
- #client TSIG verification fails, the client MUST close the connection.
299
- #If the client does not receive TSIG records frequently enough (as
300
- #specified above) it SHOULD assume the connection has been hijacked
301
- #and it SHOULD close the connection. The client SHOULD treat this the
302
- #same way as they would any other interrupted transfer (although the
303
- #exact behavior is not specified).
304
- #-----
305
- #
306
- # Each time a new envelope comes in, this method is called on the QUERY TSIG RR.
307
- # It will set the response tsigstate to :Verified :Intermediate or :Failed
308
- # as appropriate.
309
-
310
- # Keep digest going of messages as they come in (and mark them intermediate)
311
- # When TSIG comes in, work out what key should be and check. If OK, mark
312
- # verified. Can reset digest then.
313
- if (!@buf)
314
- @num_envelopes = 0
315
- @last_signed = 0
316
- end
317
- @num_envelopes += 1
318
- if (!response.tsig)
319
- if ((@num_envelopes > 1) && (@num_envelopes - @last_signed < 100))
320
- Dnsruby.log.debug("Receiving intermediate envelope in TSIG TCP session")
321
- response.tsigstate = :Intermediate
322
- response.tsigerror = RCode.NOERROR
323
- @buf = @buf + response_bytes
324
- return
325
- else
326
- response.tsigstate = :Failed
327
- Dnsruby.log.error("Expecting signed packet")
328
- return false
329
- end
330
- end
331
- @last_signed = @num_envelopes
332
-
333
- # We have a TSIG - process it!
334
- tsig = response.tsig
335
- if (@num_envelopes == 1)
336
- Dnsruby.log.debug("First response in TSIG TCP session - verifying normally")
337
- # Process it as a standard answer
338
- ok = verify(@query, response, response_bytes)
339
- if (ok)
340
- mac_bytes = MessageEncoder.new {|m|
341
- m.put_pack('n', tsig.mac_size)
342
- m.put_bytes(tsig.mac)
343
- }.to_s
344
- @buf = mac_bytes
345
- end
346
- return ok
347
- end
348
- Dnsruby.log.debug("Processing TSIG on TSIG TCP session")
349
-
350
- if (!verify_common(response))
351
- return false
352
- end
353
-
354
- # Now add the current message data - remember to frig the arcount
355
- response_bytes = Header.decrement_arcount_encoded(response_bytes)
356
- @buf += response_bytes[0, response.tsigstart]
357
-
358
- # Let's add the timers
359
- timers_data = MessageEncoder.new { |msg|
360
- time_high = (tsig.time_signed >> 32)
361
- time_low = (tsig.time_signed & 0xFFFFFFFF)
362
- msg.put_pack('nN', time_high, time_low)
363
- msg.put_pack('n', tsig.fudge)
364
- }.to_s
365
- @buf += timers_data
366
-
367
- mac = calculate_mac(tsig.algorithm, @buf)
368
-
369
- if (mac != tsig.mac)
370
- Dnsruby.log.error("TSIG Verify error on TSIG TCP session")
371
- response.tsigstate = :Failed
372
- return false
373
- end
374
- mac_bytes = MessageEncoder.new {|m|
375
- m.put_pack('n', mac.length)
376
- m.put_bytes(mac)
377
- }.to_s
378
- @buf=mac_bytes
379
-
380
- response.tsigstate = :Verified
381
- response.tsigerror = RCode.NOERROR
382
- return true
383
- end
384
-
385
-
386
- TypeValue = Types::TSIG #:nodoc: all
387
- ClassValue = nil #:nodoc: all
388
- ClassHash[[TypeValue, Classes::ANY]] = self #:nodoc: all
389
-
390
- #Gets or sets the domain name that specifies the name of the algorithm.
391
- #The only algorithms currently supported are hmac-md5 and hmac-sha1.
392
- #
393
- # rr.algorithm=(algorithm_name)
394
- # print "algorithm = ", rr.algorithm, "\n"
395
- #
396
- attr_reader :algorithm
397
-
398
- #Gets or sets the signing time as the number of seconds since 1 Jan 1970
399
- #00:00:00 UTC.
400
- #
401
- #The default signing time is the current time.
402
- #
403
- # rr.time_signed=(time)
404
- # print "time signed = ", rr.time_signed, "\n"
405
- #
406
- attr_accessor :time_signed
407
-
408
- #Gets or sets the "fudge", i.e., the seconds of error permitted in the
409
- #signing time.
410
- #
411
- #The default fudge is 300 seconds.
412
- #
413
- # rr.fudge=(60)
414
- # print "fudge = ", rr.fudge, "\n"
415
- #
416
- attr_reader :fudge
417
-
418
- #Returns the number of octets in the message authentication code (MAC).
419
- #The programmer must call a Net::DNS::Packet object's data method
420
- #before this will return anything meaningful.
421
- #
422
- # print "MAC size = ", rr.mac_size, "\n"
423
- #
424
- attr_accessor :mac_size
425
-
426
- #Returns the message authentication code (MAC) as a string of hex
427
- #characters. The programmer must call a Net::DNS::Packet object's
428
- #data method before this will return anything meaningful.
429
- #
430
- # print "MAC = ", rr.mac, "\n"
431
- #
432
- attr_accessor :mac
433
-
434
- #Gets or sets the original message ID.
435
- #
436
- # rr.original_id(12345)
437
- # print "original ID = ", rr.original_id, "\n"
438
- #
439
- attr_accessor :original_id
440
-
441
- #Returns the RCODE covering TSIG processing. Common values are
442
- #NOERROR, BADSIG, BADKEY, and BADTIME. See RFC 2845 for details.
443
- #
444
- # print "error = ", rr.error, "\n"
445
- #
446
- attr_accessor :error
447
-
448
- #Returns the length of the Other Data. Should be zero unless the
449
- #error is BADTIME.
450
- #
451
- # print "other len = ", rr.other_size, "\n"
452
- #
453
- attr_accessor :other_size
454
-
455
- #Returns the Other Data. This field should be empty unless the
456
- #error is BADTIME, in which case it will contain the server's
457
- #time as the number of seconds since 1 Jan 1970 00:00:00 UTC.
458
- #
459
- # print "other data = ", rr.other_data, "\n"
460
- #
461
- attr_accessor :other_data
462
-
463
- #Stores the secret key used for signing/verifying messages.
464
- attr_accessor :key
465
-
466
- def init_defaults
467
- # @TODO@ Have new() method which takes key_name and key?
468
- @algorithm = DEFAULT_ALGORITHM
469
- @fudge = DEFAULT_FUDGE
470
- @mac_size = 0
471
- @mac = ""
472
- @original_id = rand(65536)
473
- @error = 0
474
- @other_size = 0
475
- @other_data = ""
476
- @time_signed = nil
477
- @buf = nil
478
-
479
- # RFC 2845 Section 2.3
480
- @klass = Classes.ANY
481
-
482
- @ttl = 0 # RFC 2845 Section 2.3
483
- end
484
-
485
- def from_data(data) #:nodoc: all
486
- @algorithm, @time_signed, @fudge, @mac_size, @mac, @original_id, @error, @other_size, @other_data = data
487
- end
488
-
489
- def name=(n)
490
- if (n.instance_of?String)
491
- n = Name.create(n)
492
- end
493
- if (!n.absolute?)
494
- @name = Name.create(n.to_s + ".")
495
- else
496
- @name = n
497
- end
498
- end
499
-
500
- # Create the RR from a standard string
501
- def from_string(str) #:nodoc: all
502
- parts = str.split("[:/]")
503
- if (parts.length < 2 || parts.length > 3)
504
- raise ArgumentException.new("Invalid TSIG key specification")
505
- end
506
- if (parts.length == 3)
507
- return TSIG.new(parts[0], parts[1], parts[2]);
508
- else
509
- return TSIG.new(HMAC_MD5, parts[0], parts[1]);
510
- end
511
- end
512
-
513
- #Set the algorithm to use to generate the HMAC
514
- #Supported values are :
515
- #* hmac-md5
516
- #* hmac-sha1
517
- #* hmac-sha256
518
- def algorithm=(alg)
519
- if (alg.class == String)
520
- if (alg.downcase=="hmac-md5")
521
- @algorithm = HMAC_MD5;
522
- elsif (alg.downcase=="hmac-sha1")
523
- @algorithm = HMAC_SHA1;
524
- elsif (alg.downcase=="hmac-sha256")
525
- @algorithm = HMAC_SHA256;
526
- else
527
- raise ArgumentError.new("Invalid TSIG algorithm")
528
- end
529
- elsif (alg.class == Name)
530
- if (alg!=HMAC_MD5 && alg!=HMAC_SHA1 && alg!=HMAC_SHA256)
531
- raise ArgumentException.new("Invalid TSIG algorithm")
532
- end
533
- @algorithm=alg
534
- else
535
- raise ArgumentError.new("#{alg.class} not valid type for Dnsruby::RR::TSIG#algorithm= - use String or Name")
536
- end
537
- Dnsruby.log.debug{"Using #{@algorithm.to_s} algorithm"}
538
- end
539
-
540
- def fudge=(f)
541
- if (f < 0 || f > 0x7FFF)
542
- @fudge = DEFAULT_FUDGE
543
- else
544
- @fudge = f
545
- end
546
- end
547
-
548
- def rdata_to_string
549
- rdatastr=""
550
- if (@algorithm!=nil)
551
- error = @error
552
- error = "UNDEFINED" unless error!=nil
553
- rdatastr = "#{@original_id} #{@time_signed} #{@algorithm.to_s(true)} #{error}";
554
- if (@other_size > 0 && @other_data!=nil)
555
- rdatastr += " #{@other_data}"
556
- end
557
- rdatastr += " " + mac.unpack("H*").to_s
558
- end
559
-
560
- return rdatastr
561
- end
562
-
563
- def encode_rdata(msg, canonical=false) #:nodoc: all
564
- # Name needs to be added with no compression - done in Dnsruby::Message#encode
565
- msg.put_name(@algorithm.downcase, true)
566
- time_high = (@time_signed >> 32)
567
- time_low = (@time_signed & 0xFFFFFFFF)
568
- msg.put_pack('nN', time_high, time_low)
569
- msg.put_pack('n', @fudge)
570
- msg.put_pack('n', @mac_size)
571
- msg.put_bytes(@mac)
572
- msg.put_pack('n', @original_id)
573
- msg.put_pack('n', @error)
574
- msg.put_pack('n', @other_size)
575
- msg.put_bytes(@other_data)
576
- end
577
-
578
- def self.decode_rdata(msg) #:nodoc: all
579
- alg=msg.get_name
580
- time_high, time_low = msg.get_unpack("nN")
581
- time_signed = (time_high << 32) + time_low
582
- fudge, = msg.get_unpack("n")
583
- mac_size, = msg.get_unpack("n")
584
- mac = msg.get_bytes(mac_size)
585
- original_id, = msg.get_unpack("n")
586
- error, = msg.get_unpack("n")
587
- other_size, = msg.get_unpack("n")
588
- other_data = msg.get_bytes(other_size)
589
- return self.new([alg, time_signed, fudge, mac_size, mac, original_id, error, other_size, other_data])
590
- end
591
- end
592
- end
593
- end