gitlab-net-dns 0.12.0 → 0.13.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 626fddeccebd199f0753f59a1f0da00bf17c923ab59863f6dcf4f1712e565aa9
4
- data.tar.gz: 266c1c5e8b273c3b09305cca8a96127b4d46bfe9396ceb103ef3278edef54101
3
+ metadata.gz: da76ca67ffda2850455d743e3485328b73296a7cfdca4808e8540fc0ba4b2593
4
+ data.tar.gz: c854da335de562911f61a177047bdcda77541be3c8647be8bc78a10ca0918f62
5
5
  SHA512:
6
- metadata.gz: f17432960ab586b0e2d74dc9d3d8cdad69a477c050f20139038155825b4dcd116d41fa8b423203310fd88cd8510f49086db89d2fee372219eb72fe5d39a56cf1
7
- data.tar.gz: b357ac43e0927bccd981530f026f4af77f3a1da4d2263966621a9744a62781bf44f7438f383b404d3194f5a9f1f0f16ea490ac8116ad1299683aa5a408405af9
6
+ metadata.gz: 2262bc9366375314c0119d96f2163f658b181d0b6bb1e6044aee62707ccf4da1c89ab8da66c508f3b0155d7fa240c583697cf4b4431b3bfe4bf04057b08a7628
7
+ data.tar.gz: 1a157339c0ee195365c5aa20692c8496d1401a7eb2a0fb6f48db3ecbc346f42ab7ff8e3bf3c454f851554234a66bcd83dd2d4d1568f22a989ba61812be716562
data/.rubocop_todo.yml CHANGED
@@ -11,7 +11,7 @@
11
11
  # Include: **/*.gemspec
12
12
  Gemspec/RequiredRubyVersion:
13
13
  Exclude:
14
- - 'net-dns.gemspec'
14
+ - 'gitlab-net-dns.gemspec'
15
15
 
16
16
 
17
17
  # Offense count: 2
data/README.md CHANGED
@@ -17,16 +17,16 @@ Ruby >= 2.1
17
17
 
18
18
  ## Installation
19
19
 
20
- The best way to install this library is via [RubyGems](https://rubygems.org/).
20
+ The best way to install this library is via [RubyGems](https://rubygems.org/gems/gitlab-net-dns/).
21
21
 
22
22
  ```
23
- gem install net-dns
23
+ gem install gitlab-net-dns
24
24
  ```
25
25
 
26
26
 
27
27
  ## API Documentation
28
28
 
29
- Visit the page http://rdoc.info/gems/net-dns
29
+ Visit the page http://rdoc.info/gems/gitlab-net-dns
30
30
 
31
31
 
32
32
  ## Trivial resolver
@@ -92,7 +92,10 @@ module Net
92
92
  class NoResponseError < Error
93
93
  end
94
94
 
95
- # An hash with the defaults values of almost all the
95
+ class ResolverPermissionError < Error
96
+ end
97
+
98
+ # A hash with the default values of almost all the
96
99
  # configuration parameters of a resolver object. See
97
100
  # the description for each parameter to have an
98
101
  # explanation of its usage.
@@ -315,7 +318,16 @@ module Net
315
318
  # #=> ["192.168.0.1","192.168.0.2"]
316
319
  #
317
320
  def nameservers
318
- @config[:nameservers].map(&:to_s)
321
+ @config[:nameservers].map do |entry|
322
+ case entry
323
+ in IPAddr
324
+ entry.to_s
325
+ in [IPAddr]
326
+ [entry[0].to_s]
327
+ in [IPAddr, Integer]
328
+ [entry[0].to_s, entry[1]]
329
+ end
330
+ end
319
331
  end
320
332
 
321
333
  alias nameserver nameservers
@@ -326,48 +338,38 @@ module Net
326
338
  # res.nameservers = "192.168.0.1"
327
339
  # res.nameservers = ["192.168.0.1","192.168.0.2"]
328
340
  #
329
- # If you want you can specify the addresses as IPAddr instances.
341
+ # If you want, you can specify the addresses as IPAddr instances.
330
342
  #
331
- # ip = IPAddr.new("192.168.0.3")
332
- # res.nameservers << ip
333
- # #=> ["192.168.0.1","192.168.0.2","192.168.0.3"]
343
+ # res.nameservers = IPAddr.new("192.168.0.3")
334
344
  #
335
345
  # The default is 127.0.0.1 (localhost)
336
346
  #
337
347
  def nameservers=(arg)
338
- case arg
339
- when String
340
- begin
341
- @config[:nameservers] = [IPAddr.new(arg)]
342
- @logger.info "Nameservers list changed to value #{@config[:nameservers].inspect}"
343
- rescue ArgumentError # arg is in the name form, not IP
344
- nameservers_from_name(arg)
345
- end
346
- when IPAddr
347
- @config[:nameservers] = [arg]
348
- @logger.info "Nameservers list changed to value #{@config[:nameservers].inspect}"
349
- when Array
350
- @config[:nameservers] = []
351
- arg.each do |x|
352
- val = case x
353
- when String
354
- begin
355
- IPAddr.new(x)
356
- rescue ArgumentError
357
- nameservers_from_name(arg)
358
- return
359
- end
360
- when IPAddr
361
- x
362
- else
363
- raise ArgumentError, "Wrong argument format"
348
+ @config[:nameservers] = Array(arg).flat_map do |entry|
349
+ case entry
350
+ in String
351
+ begin
352
+ IPAddr.new(entry)
353
+ rescue ArgumentError
354
+ nameservers_from_name(entry)
364
355
  end
365
- @config[:nameservers] << val
356
+ in IPAddr
357
+ entry
358
+ in [String]
359
+ [[IPAddr.new(entry[0])]]
360
+ in [IPAddr]
361
+ [[entry[0]]]
362
+ in [String, Integer]
363
+ validate_port!(entry[1])
364
+ [[IPAddr.new(entry[0]), entry[1]]]
365
+ in [IPAddr, Integer]
366
+ validate_port!(entry[1])
367
+ [[entry[0], entry[1]]]
368
+ else
369
+ raise ArgumentError, "Wrong argument format, neither String, Array nor IPAddr"
366
370
  end
367
- @logger.info "Nameservers list changed to value #{@config[:nameservers].inspect}"
368
- else
369
- raise ArgumentError, "Wrong argument format, neither String, Array nor IPAddr"
370
371
  end
372
+ @logger.info "Nameservers list changed to value #{@config[:nameservers].inspect}"
371
373
  end
372
374
  alias_method("nameserver=", "nameservers=")
373
375
 
@@ -402,8 +404,7 @@ module Net
402
404
  # The default is port 53.
403
405
  #
404
406
  def port=(num)
405
- (0..65_535).cover?(num) or
406
- raise(ArgumentError, "Wrong port number #{num}")
407
+ validate_port!(num)
407
408
 
408
409
  @config[:port] = num
409
410
  @logger.info "Port number changed to #{num}"
@@ -422,7 +423,7 @@ module Net
422
423
  #
423
424
  # res.source_port = 40000
424
425
  #
425
- # Note that if you want to set a port you need root priviledges, as
426
+ # Note that if you want to set a port, you need root privileges, as
426
427
  # raw sockets will be used to generate packets. The class will then
427
428
  # generate the exception ResolverPermissionError if you're not root.
428
429
  #
@@ -430,10 +431,8 @@ module Net
430
431
  # underlaying layers.
431
432
  #
432
433
  def source_port=(num)
433
- root? or
434
- raise(ResolverPermissionError, "Are you root?")
435
- (0..65_535).cover?(num) or
436
- raise(ArgumentError, "Wrong port number #{num}")
434
+ raise(ResolverPermissionError, "Are you root?") unless root?
435
+ validate_port!(num)
437
436
 
438
437
  @config[:source_port] = num
439
438
  end
@@ -871,43 +870,6 @@ module Net
871
870
  query(name + ".", type, cls)
872
871
  end
873
872
 
874
- # Performs a DNS query for the given name; the search list
875
- # is not applied. If the name doesn't contain any dots and
876
- # +defname+ is true then the default domain will be appended.
877
- #
878
- # The record type and class can be omitted; they default to +A+
879
- # and +IN+. If the name looks like an IP address (IPv4 or IPv6),
880
- # then an appropriate PTR query will be performed.
881
- #
882
- # packet = res.query('mailhost')
883
- # packet = res.query('mailhost.example.com')
884
- # packet = res.query('example.com', Net::DNS::MX)
885
- # packet = res.query('user.passwd.example.com', Net::DNS::TXT, Net::DNS::HS)
886
- #
887
- # If the name is an IP address (Ipv4 or IPv6), in the form of a string
888
- # or a +IPAddr+ object, then an appropriate PTR query will be performed:
889
- #
890
- # ip = IPAddr.new("172.16.100.2")
891
- # packet = res.query(ip)
892
- # packet = res.query("192.168.10.254")
893
- #
894
- # Returns a Net::DNS::Packet object. If you need to examine the response
895
- # packet whether it contains any answers or not, use the Resolver#query
896
- # method instead.
897
- #
898
- def query(name, type = Net::DNS::A, cls = Net::DNS::IN)
899
- return send(name, type, cls) if name.class == IPAddr
900
-
901
- # If the name doesn't contain any dots then append the default domain.
902
- if name !~ /\./ && name !~ /:/ && @config[:defname]
903
- name += "." + @config[:domain]
904
- end
905
-
906
- @logger.debug "Query(#{name},#{Net::DNS::RR::Types.new(type)},#{Net::DNS::RR::Classes.new(cls)})"
907
-
908
- send(name, type, cls)
909
- end
910
-
911
873
  # Performs a DNS query for the given name. Neither the
912
874
  # searchlist nor the default domain will be appended.
913
875
  #
@@ -1293,11 +1255,9 @@ module Net
1293
1255
  # res.nameservers = "192.168.0.1"
1294
1256
  # res.nameservers = ["192.168.0.1","192.168.0.2"]
1295
1257
  #
1296
- # If you want you can specify the addresses as IPAddr instances.
1258
+ # If you want, you can specify the addresses as IPAddr instances.
1297
1259
  #
1298
- # ip = IPAddr.new("192.168.0.3")
1299
- # res.nameservers << ip
1300
- # #=> ["192.168.0.1","192.168.0.2","192.168.0.3"]
1260
+ # res.nameservers = IPAddr.new("192.168.0.3")
1301
1261
  #
1302
1262
  # The default is 127.0.0.1 (localhost)
1303
1263
  #
@@ -1639,7 +1599,7 @@ module Net
1639
1599
  arr << ip
1640
1600
  end
1641
1601
  end
1642
- @config[:nameservers] << arr
1602
+ arr
1643
1603
  end
1644
1604
 
1645
1605
  def make_query_packet(string, type, cls)
@@ -1675,17 +1635,17 @@ module Net
1675
1635
  ans = nil
1676
1636
  length = [packet_data.size].pack("n")
1677
1637
 
1678
- @config[:nameservers].each do |ns|
1638
+ nameserver_port_pairs.each do |(ns, ns_port)|
1679
1639
  begin
1680
1640
  buffer = ""
1681
1641
  socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
1682
1642
  socket.bind(Socket.pack_sockaddr_in(@config[:source_port], @config[:source_address].to_s))
1683
1643
 
1684
- sockaddr = Socket.pack_sockaddr_in(@config[:port], ns.to_s)
1644
+ sockaddr = Socket.pack_sockaddr_in(ns_port, ns.to_s)
1685
1645
 
1686
1646
  @config[:tcp_timeout].timeout do
1687
1647
  socket.connect(sockaddr)
1688
- @logger.info "Contacting nameserver #{ns} port #{@config[:port]}"
1648
+ @logger.info "Contacting nameserver #{ns} port #{ns_port}"
1689
1649
  socket.write(length + packet_data)
1690
1650
  ans = socket.recv(Net::DNS::INT16SZ)
1691
1651
  len = ans.unpack("n")[0]
@@ -1708,7 +1668,7 @@ module Net
1708
1668
  next
1709
1669
  end
1710
1670
  end
1711
- return [buffer, ["", @config[:port], ns.to_s, ns.to_s]]
1671
+ return [buffer, ["", ns_port, ns.to_s, ns.to_s]]
1712
1672
  rescue Timeout::Error
1713
1673
  @logger.warn "Nameserver #{ns} not responding within TCP timeout, trying next one"
1714
1674
  next
@@ -1727,15 +1687,15 @@ module Net
1727
1687
 
1728
1688
  ans = nil
1729
1689
  response = ""
1730
- @config[:nameservers].each do |ns|
1690
+ nameserver_port_pairs.each do |(ns, ns_port)|
1731
1691
  begin
1732
1692
  @config[:udp_timeout].timeout do
1733
- @logger.info "Contacting nameserver #{ns} port #{@config[:port]}"
1693
+ @logger.info "Contacting nameserver #{ns} port #{ns_port}"
1734
1694
  ans = if ns.ipv6?
1735
- socket6.send(packet_data, 0, ns.to_s, @config[:port])
1695
+ socket6.send(packet_data, 0, ns.to_s, ns_port)
1736
1696
  socket6.recvfrom(@config[:packet_size])
1737
1697
  else
1738
- socket4.send(packet_data, 0, ns.to_s, @config[:port])
1698
+ socket4.send(packet_data, 0, ns.to_s, ns_port)
1739
1699
  socket4.recvfrom(@config[:packet_size])
1740
1700
  end
1741
1701
  end
@@ -1748,6 +1708,22 @@ module Net
1748
1708
  ans
1749
1709
  end
1750
1710
 
1711
+ def nameserver_port_pairs
1712
+ @config[:nameservers].map { |entry| Array(entry) }.map { |ns, ns_port| [ns, ns_port || port] }
1713
+ end
1714
+
1715
+ def validate_port!(port)
1716
+ raise(ArgumentError, "Wrong port number #{port}") unless valid_port?(port)
1717
+ end
1718
+
1719
+ def valid_port?(port)
1720
+ (0..65_535).cover?(port)
1721
+ end
1722
+
1723
+ def root?
1724
+ Process.euid == 0
1725
+ end
1726
+
1751
1727
  # FIXME: a ? method should never raise.
1752
1728
  def valid?(name)
1753
1729
  name !~ /[^-\w\.]/ or
@@ -3,6 +3,6 @@
3
3
  module Net
4
4
  module DNS
5
5
  # The current library version.
6
- VERSION = "0.12.0"
6
+ VERSION = "0.13.0"
7
7
  end
8
8
  end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+ require 'net/dns/resolver/timeouts'
3
+
4
+ describe Net::DNS::Resolver do
5
+ it 'executes UDP query' do
6
+ ipv4_sock = instance_double(UDPSocket, bind: 0, send: 0)
7
+ ipv6_sock = instance_double(UDPSocket, bind: 0)
8
+
9
+ google_com_a_record_response = [
10
+ "A\x06\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\x06google\x03com\x00\x00\x01\x00\x01\xC0\f\x00\x01\x00\x01\x00\x00\x00I\x00\x04\x8E\xFA\xBA\xCE",
11
+ ['AF_INET', 53, '8.8.8.8', '8.8.8.8']
12
+ ]
13
+ allow(ipv4_sock).to receive(:recvfrom).and_return(google_com_a_record_response)
14
+
15
+ allow(UDPSocket).to receive(:new).and_return(ipv4_sock)
16
+ allow(UDPSocket).to receive(:new).with(Socket::AF_INET6).and_return(ipv6_sock)
17
+
18
+ resolver = Net::DNS::Resolver.new(nameservers: %w[8.8.8.8])
19
+ response = resolver.query('google.com')
20
+
21
+ expect(response.answer[0].address.to_s).to eq('142.250.186.206')
22
+ expect(ipv4_sock).to have_received(:bind).with(instance_of(String), instance_of(Integer))
23
+ expect(ipv4_sock).to have_received(:send).with(instance_of(String), 0, '8.8.8.8', 53)
24
+ expect(ipv4_sock).to have_received(:recvfrom).with(instance_of(Integer))
25
+ end
26
+
27
+ it 'executes TCP query' do
28
+ sock = instance_double(Socket, bind: 0, connect: 0, write: 0, close: nil)
29
+
30
+ allow(sock).to receive(:recv).and_return("\x00,")
31
+ google_com_a_record_response = "%\xF9\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\x06google\x03com\x00\x00\x01\x00\x01\xC0\f\x00\x01\x00\x01\x00\x00\x00\xB3\x00\x04\x8E\xFA\xBA\xCE"
32
+ allow(sock).to receive(:recvfrom).and_return(google_com_a_record_response)
33
+
34
+ allow(Socket).to receive(:new).and_return(sock)
35
+
36
+ resolver = Net::DNS::Resolver.new(nameservers: %w[8.8.8.8], use_tcp: true)
37
+ response = resolver.query('google.com')
38
+
39
+ expect(response.answer[0].address.to_s).to eq('142.250.186.206')
40
+ expect(sock).to have_received(:bind).with(instance_of(String))
41
+ expect(sock).to have_received(:connect).with(Socket.pack_sockaddr_in(53, '8.8.8.8'))
42
+ expect(sock).to have_received(:write).with(instance_of(String))
43
+ expect(sock).to have_received(:recv)
44
+ expect(sock).to have_received(:recvfrom).with(instance_of(Integer))
45
+ expect(sock).to have_received(:close)
46
+ end
47
+ end
@@ -25,6 +25,69 @@ class ResolverTest < Minitest::Test
25
25
  assert_raises(ArgumentError) { Net::DNS::Resolver.new(:foo) }
26
26
  end
27
27
 
28
+ def test_set_port
29
+ resolver = Net::DNS::Resolver.new
30
+ assert_equal 53, resolver.port
31
+
32
+ assert_raises(ArgumentError) { resolver.port = 100_000 }
33
+ assert_equal 53, resolver.port
34
+
35
+ resolver.port = 10_053
36
+ assert_equal 10_053, resolver.port
37
+ end
38
+
39
+ def test_set_source_port
40
+ resolver = Net::DNS::Resolver.new
41
+ assert_equal 0, resolver.source_port
42
+
43
+ resolver.stub :root?, false do
44
+ assert_raises(Net::DNS::Resolver::ResolverPermissionError) { resolver.source_port = 1 }
45
+ assert_equal 0, resolver.source_port
46
+ end
47
+
48
+ resolver.stub :root?, true do
49
+ assert_raises(ArgumentError) { resolver.source_port = 100_000 }
50
+ assert_equal 0, resolver.source_port
51
+
52
+ resolver.source_port = 1
53
+ assert_equal 1, resolver.source_port
54
+ end
55
+ end
56
+
57
+ def test_set_nameservers
58
+ resolver = Net::DNS::Resolver.new nameservers: '127.0.0.1'
59
+ assert_equal ['127.0.0.1'], resolver.nameservers
60
+
61
+ assert_raises(ArgumentError) { resolver.nameservers = 1 }
62
+ assert_equal ['127.0.0.1'], resolver.nameservers
63
+
64
+ assert_raises(ArgumentError) { resolver.nameservers = ['192.168.1.1', 1] }
65
+ assert_equal ['127.0.0.1'], resolver.nameservers
66
+
67
+ resolver.stub :nameservers_from_name, [IPAddr.new('192.168.1.1')] do
68
+ assert_raises(ArgumentError) { resolver.nameservers = ['test.com', 1] }
69
+ assert_equal ['127.0.0.1'], resolver.nameservers
70
+
71
+ resolver.nameservers = 'test.com'
72
+ assert_equal ['192.168.1.1'], resolver.nameservers
73
+
74
+ resolver.nameservers = ['test.com']
75
+ assert_equal ['192.168.1.1'], resolver.nameservers
76
+
77
+ resolver.nameservers = ['192.168.1.2', 'test.com', IPAddr.new('192.168.1.3')]
78
+ assert_equal ['192.168.1.2', '192.168.1.1', '192.168.1.3'], resolver.nameservers
79
+ end
80
+
81
+ resolver.nameservers = [['192.168.1.1', 30053], ['192.168.1.2'], '192.168.1.3']
82
+ assert_equal [['192.168.1.1', 30053], ['192.168.1.2'], '192.168.1.3'], resolver.nameservers
83
+
84
+ resolver.nameservers = [[IPAddr.new('192.168.1.1'), 30053], [IPAddr.new('192.168.1.2')], IPAddr.new('192.168.1.3')]
85
+ assert_equal [['192.168.1.1', 30053], ['192.168.1.2'], '192.168.1.3'], resolver.nameservers
86
+
87
+ assert_raises(ArgumentError) { resolver.nameservers = [['192.168.1.1', 100_000]] }
88
+ assert_raises(ArgumentError) { resolver.nameservers = [[IPAddr.new('192.168.1.2'), 100_000]] }
89
+ end
90
+
28
91
  def test_query_with_no_nameservers_should_raise_resolvererror
29
92
  assert_raises(Net::DNS::Resolver::Error) { Net::DNS::Resolver.new(nameservers: []).query("example.com") }
30
93
  end
@@ -75,6 +138,13 @@ class ResolverTest < Minitest::Test
75
138
  assert_equal Net::DNS::IN.to_i, packet.question.first.qClass.to_i
76
139
  end
77
140
 
141
+ def test_nameserver_port_pairs
142
+ resolver = Net::DNS::Resolver.new(nameservers: [['172.16.1.1', 30_053], ['172.16.1.2'], '172.16.1.3'])
143
+ nameserver_port_pairs = resolver.send(:nameserver_port_pairs)
144
+ assert_equal ['172.16.1.1', '172.16.1.2', '172.16.1.3'], nameserver_port_pairs.map(&:first).map(&:to_s)
145
+ assert_equal [30_053, 53, 53], nameserver_port_pairs.map(&:last)
146
+ end
147
+
78
148
  def test_should_return_state_without_exception
79
149
  res = Net::DNS::Resolver.new
80
150
  assert_nothing_raised { res.state }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-net-dns
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marco Ceresa
8
8
  - Simone Carletti
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-05-03 00:00:00.000000000 Z
11
+ date: 2025-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: logger
@@ -122,6 +122,7 @@ files:
122
122
  - spec/unit/resolver/dns_timeout_spec.rb
123
123
  - spec/unit/resolver/tcp_timeout_spec.rb
124
124
  - spec/unit/resolver/udp_timeout_spec.rb
125
+ - spec/unit/resolver_spec.rb
125
126
  - test/test_helper.rb
126
127
  - test/unit/header_test.rb
127
128
  - test/unit/names_test.rb
@@ -165,6 +166,7 @@ test_files:
165
166
  - spec/unit/resolver/dns_timeout_spec.rb
166
167
  - spec/unit/resolver/tcp_timeout_spec.rb
167
168
  - spec/unit/resolver/udp_timeout_spec.rb
169
+ - spec/unit/resolver_spec.rb
168
170
  - test/test_helper.rb
169
171
  - test/unit/header_test.rb
170
172
  - test/unit/names_test.rb