resolv 0.7.1 → 0.7.2

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 (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/resolv.rb +90 -11
  3. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c4c4e60f6c23abc6f116dfbea5e531d20f99eb85025e4682d3d85f580e17d09d
4
- data.tar.gz: e609b5a2a67f67b5d7c616a2a3340d5ab3af305a29f66ab800785d62466ab883
3
+ metadata.gz: 38de4f14ddb183350d35593550caa34f9694644fb9d2fc79bd275d92d17ee338
4
+ data.tar.gz: 00d4977e89fb7cd8ec4a772c481d63e49fd4441b90c7ec5be42a79294ab3da19
5
5
  SHA512:
6
- metadata.gz: 3eab1f21df971bd56cd9e23429fdef5da84a502c6d441dcf4cb3ff06fbf2c5222c7cd72b6d17a466d46b956bdeeeecfde0bc0254d78c37d73d1fd1c915bc0912
7
- data.tar.gz: e81e097c7fc424ba72f2f84a07d933cb7bfb001f019ba2babb440c2a94e5aed2f38df688934cd0a35a5ed583ae73969b56ea7e6a92f1e8cdf4875a210d331003
6
+ metadata.gz: 175ca63aa1f82ebabc499bbcd8eedf17c33ff220c439187a1c5778ca2e74926d15651a720c0bb5f615a698747252d8f9cd82c5db5fb25d28a4d1e63cb696acf1
7
+ data.tar.gz: 8789721febc5b7a96a8bcfdc51dd503afefa648a6d7057e6951b77d1fb514c613e35524ef9680e4ef6d4ad49e310a0fa2d1e92a972eae0e8f23969519c7db1d9
data/lib/resolv.rb CHANGED
@@ -35,7 +35,7 @@ require 'rbconfig'
35
35
  class Resolv
36
36
 
37
37
  # The version string
38
- VERSION = "0.7.1"
38
+ VERSION = "0.7.2"
39
39
 
40
40
  ##
41
41
  # Looks up the first IP address for +name+.
@@ -1253,6 +1253,13 @@ class Resolv
1253
1253
 
1254
1254
  class Str # :nodoc:
1255
1255
  def initialize(string)
1256
+ # A label is limited to 63 octets. [RFC 1035 2.3.4] Checking it here
1257
+ # makes it an invariant of the object: every label, however it was
1258
+ # built, fits in its length octet and cannot wrap it. Callers turn
1259
+ # this into the error their own contract promises.
1260
+ if string.bytesize > 63
1261
+ raise ArgumentError, "DNS label is too long (#{string.bytesize} bytes, max 63): #{string.inspect}"
1262
+ end
1256
1263
  @string = string
1257
1264
  # case insensivity of DNS labels doesn't apply non-ASCII characters. [RFC 4343]
1258
1265
  # This assumes @string is given in ASCII compatible encoding.
@@ -1298,7 +1305,26 @@ class Resolv
1298
1305
  when Name
1299
1306
  return arg
1300
1307
  when String
1301
- return Name.new(Label.split(arg), /\.\z/ =~ arg ? true : false)
1308
+ # A hostname is runtime data rather than a programming mistake, so
1309
+ # both size limits surface as ResolvError to stay rescuable alongside
1310
+ # the rest of name resolution. The type check below is a caller
1311
+ # mistake and keeps raising ArgumentError.
1312
+ begin
1313
+ labels = Label.split(arg)
1314
+ rescue ArgumentError => e
1315
+ raise ResolvError.new(e.message)
1316
+ end
1317
+ # Label::Str enforces the per-label limit. Only the total is knowable
1318
+ # here, and it counts the encoded form, so size starts at 1 for the
1319
+ # root label's terminating zero octet. [RFC 1035 2.3.4, 3.1]
1320
+ size = 1
1321
+ labels.each do |label|
1322
+ size += 1 + label.string.bytesize
1323
+ if size > 255
1324
+ raise ResolvError.new("DNS name is too long (#{size} octets, max 255): #{arg.inspect}")
1325
+ end
1326
+ end
1327
+ return Name.new(labels, /\.\z/ =~ arg ? true : false)
1302
1328
  else
1303
1329
  raise ArgumentError.new("cannot interpret as DNS name: #{arg.inspect}")
1304
1330
  end
@@ -1420,12 +1446,24 @@ class Resolv
1420
1446
  @rd == other.rd &&
1421
1447
  @ra == other.ra &&
1422
1448
  @rcode == other.rcode &&
1423
- @question == other.question &&
1449
+ question_equal?(other.question) &&
1424
1450
  @answer == other.answer &&
1425
1451
  @authority == other.authority &&
1426
1452
  @additional == other.additional
1427
1453
  end
1428
1454
 
1455
+ # A question holds the resource class itself, and decoding creates a fresh
1456
+ # class for each unknown type, so the classes cannot be compared by
1457
+ # identity alone.
1458
+ private def question_equal?(other_question) # :nodoc:
1459
+ return false unless @question.length == other_question.length
1460
+ @question.zip(other_question) {|(name, typeclass), (o_name, o_typeclass)|
1461
+ return false unless name == o_name &&
1462
+ Resource::Generic.type_class_equal?(typeclass, o_typeclass)
1463
+ }
1464
+ return true
1465
+ end
1466
+
1429
1467
  def add_question(name, typeclass)
1430
1468
  @question << [Name.create(name), typeclass]
1431
1469
  end
@@ -1532,8 +1570,15 @@ class Resolv
1532
1570
  end
1533
1571
 
1534
1572
  def put_string(d)
1535
- self.put_pack("C", d.length)
1536
- @data << d
1573
+ s = d.to_s
1574
+ # A character-string is prefixed by a single length octet, so it can
1575
+ # hold at most 255 octets. [RFC 1035 3.3] Reject anything longer to
1576
+ # avoid silently truncating the length to its low 8 bits (mod 256).
1577
+ if s.bytesize > 255
1578
+ raise ArgumentError, "character-string is too long (#{s.bytesize} bytes, max 255): #{s.inspect}"
1579
+ end
1580
+ self.put_pack("C", s.bytesize)
1581
+ @data << s
1537
1582
  end
1538
1583
 
1539
1584
  def put_string_list(ds)
@@ -1563,7 +1608,17 @@ class Resolv
1563
1608
  end
1564
1609
 
1565
1610
  def put_label(d)
1566
- self.put_string(d.to_s)
1611
+ s = d.to_s
1612
+ # Label::Str applies this limit when a label is built, so what is left
1613
+ # for here is a raw string handed straight to put_labels. The two ways
1614
+ # an over-long label goes wrong differ: 64 to 255 octets write a length
1615
+ # octet in the reserved or compression pointer range, and 256 or more
1616
+ # wrap it mod 256. Either way the encoded name stops being the name the
1617
+ # caller asked for. [RFC 1035 2.3.4, 4.1.4]
1618
+ if s.bytesize > 63
1619
+ raise ArgumentError, "DNS label is too long (#{s.bytesize} bytes, max 63): #{s.inspect}"
1620
+ end
1621
+ self.put_string(s)
1567
1622
  end
1568
1623
  end
1569
1624
 
@@ -1689,7 +1744,9 @@ class Resolv
1689
1744
  prev_index = @index
1690
1745
  save_index = nil
1691
1746
  d = []
1692
- size = -1
1747
+ # size counts the encoded form, so it starts at 1 for the root
1748
+ # label's terminating zero octet. [RFC 1035 3.1]
1749
+ size = 1
1693
1750
  while true
1694
1751
  raise DecodeError.new("limit exceeded") if @limit <= @index
1695
1752
  case @data.getbyte(@index)
@@ -1720,6 +1777,11 @@ class Resolv
1720
1777
 
1721
1778
  def get_label
1722
1779
  return Label::Str.new(self.get_string)
1780
+ rescue ArgumentError => e
1781
+ # A length octet of 64..191 is reserved rather than a label length,
1782
+ # but this decoder used to read it as one. [RFC 1035 4.1.4] Report it
1783
+ # the way the rest of a malformed message is reported.
1784
+ raise DecodeError.new(e.message)
1723
1785
  end
1724
1786
 
1725
1787
  def get_question
@@ -1907,8 +1969,9 @@ class Resolv
1907
1969
  key_name = :"key#{key_number}"
1908
1970
  c.const_set(:KeyName, key_name)
1909
1971
  c.const_set(:KeyNumber, key_number)
1910
- self.const_set(:"Key#{key_number}", c)
1911
- ClassHash[key_name] = ClassHash[key_number] = c
1972
+ # Not registered in a constant or in ClassHash. ClassHash creates a
1973
+ # class for every unknown SvcParamKey, so registering them
1974
+ # permanently would let a malicious response exhaust memory.
1912
1975
  return c
1913
1976
  end
1914
1977
  end
@@ -2215,12 +2278,28 @@ class Resolv
2215
2278
  return self.new(msg.get_bytes)
2216
2279
  end
2217
2280
 
2281
+ # create makes a fresh class for each decoded resource, so the type and
2282
+ # class values have to be compared instead of the class itself.
2283
+ def self.type_class_equal?(klass, other) # :nodoc:
2284
+ return true if klass.equal?(other)
2285
+ Generic > klass && Generic > other &&
2286
+ klass::TypeValue == other::TypeValue &&
2287
+ klass::ClassValue == other::ClassValue
2288
+ end
2289
+
2290
+ def ==(other) # :nodoc:
2291
+ return other.is_a?(Generic) &&
2292
+ Generic.type_class_equal?(self.class, other.class) &&
2293
+ @data == other.data
2294
+ end
2295
+
2218
2296
  def self.create(type_value, class_value) # :nodoc:
2219
2297
  c = Class.new(Generic)
2220
2298
  c.const_set(:TypeValue, type_value)
2221
2299
  c.const_set(:ClassValue, class_value)
2222
- Generic.const_set("Type#{type_value}_Class#{class_value}", c)
2223
- ClassHash[[type_value, class_value]] = c
2300
+ # Not registered in a constant or in ClassHash. get_class creates a
2301
+ # class for every unknown (type, class) pair, so registering them
2302
+ # permanently would let a malicious response exhaust memory.
2224
2303
  return c
2225
2304
  end
2226
2305
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resolv
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tanaka Akira