sparoid 2.1.2 → 2.2.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.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +1 -1
- data/CHANGELOG.md +8 -0
- data/Gemfile +1 -0
- data/lib/sparoid/version.rb +1 -1
- data/lib/sparoid.rb +31 -9
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 71eaf9ec6bae245550f5134ddd360754aa3b360342551676bea056083a56ee8b
|
|
4
|
+
data.tar.gz: d97abd87405cd9c65bc96583648f6f2075867b08bab919e8871ed95de5e2e4f0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4a4426c422d8c973596758cdfeed9e23a256aa697605e9beaa9c1aa6b06f14d2fbcf5712a8fd44e25d830ed97f47912e0b707e5006d52139f686efdcf288cec9
|
|
7
|
+
data.tar.gz: b7df47069061130c91155b86fa8385f8ca2c77919baf1189c7513db3f2aca7fc1bff06f8b8e8911184ef8c2014bf8092e9b1933af6692a4137a5155c1923a7d1
|
data/.github/workflows/main.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## [2.2.1] - 2026-06-30
|
|
2
|
+
|
|
3
|
+
- Make Sparoid::Instance public-IP resolution thread-safe and empty-aware; raise Sparoid::PublicIPError when no public IP resolves (#25)
|
|
4
|
+
|
|
5
|
+
## [2.2.0] - 2026-05-06
|
|
6
|
+
|
|
7
|
+
- Raise when sendmsg fails for every resolved address (#23)
|
|
8
|
+
|
|
1
9
|
## [2.1.2] - 2026-04-30
|
|
2
10
|
|
|
3
11
|
- Skip addresses that fail synchronous connect in fdpass (#20)
|
data/Gemfile
CHANGED
data/lib/sparoid/version.rb
CHANGED
data/lib/sparoid.rb
CHANGED
|
@@ -22,20 +22,27 @@ module Sparoid # rubocop:disable Metrics/ModuleLength
|
|
|
22
22
|
# Send an authorization packet
|
|
23
23
|
def auth(key, hmac_key, host, port, open_for_ip: nil)
|
|
24
24
|
addrs = resolve_ip_addresses(host, port)
|
|
25
|
-
|
|
25
|
+
errors = []
|
|
26
|
+
successful_addrs = addrs.filter_map do |addr|
|
|
26
27
|
messages = generate_messages(open_for_ip)
|
|
27
28
|
data = messages.map do |message|
|
|
28
29
|
prefix_hmac(hmac_key, encrypt(key, message))
|
|
29
30
|
end
|
|
30
31
|
sendmsg(addr, data)
|
|
32
|
+
addr
|
|
33
|
+
rescue SystemCallError => e
|
|
34
|
+
errors << "#{addr.ip_address}: #{e.message}"
|
|
35
|
+
nil
|
|
31
36
|
end
|
|
32
37
|
|
|
38
|
+
raise Error, "Sparoid failed to send to any address for #{host}: #{errors.join("; ")}" if successful_addrs.empty?
|
|
39
|
+
|
|
33
40
|
# wait some time for the server to actually open the port
|
|
34
41
|
# if we don't wait the next SYN package will be dropped
|
|
35
42
|
# and it have to be redelivered, adding 1 second delay
|
|
36
43
|
sleep 0.02
|
|
37
44
|
|
|
38
|
-
|
|
45
|
+
successful_addrs
|
|
39
46
|
end
|
|
40
47
|
|
|
41
48
|
# Generate new aes and hmac keys, print to stdout
|
|
@@ -96,6 +103,8 @@ module Sparoid # rubocop:disable Metrics/ModuleLength
|
|
|
96
103
|
ips = ips.grep_v(Resolv::IPv6)
|
|
97
104
|
ips << Resolv::IPv6.create(native_ipv6)
|
|
98
105
|
end
|
|
106
|
+
raise PublicIPError, "Sparoid could not resolve a public IP to knock from" if ips.empty?
|
|
107
|
+
|
|
99
108
|
ips.map { |i| message(i) }
|
|
100
109
|
end
|
|
101
110
|
end
|
|
@@ -105,11 +114,9 @@ module Sparoid # rubocop:disable Metrics/ModuleLength
|
|
|
105
114
|
socket.nonblock = false
|
|
106
115
|
data.each do |packet|
|
|
107
116
|
socket.sendmsg packet, 0, addr
|
|
108
|
-
rescue StandardError => e
|
|
109
|
-
warn "Sparoid error: #{e.message}"
|
|
110
117
|
end
|
|
111
118
|
ensure
|
|
112
|
-
socket
|
|
119
|
+
socket&.close
|
|
113
120
|
end
|
|
114
121
|
|
|
115
122
|
def encrypt(key, data)
|
|
@@ -248,16 +255,31 @@ module Sparoid # rubocop:disable Metrics/ModuleLength
|
|
|
248
255
|
|
|
249
256
|
class ResolvError < Error; end
|
|
250
257
|
|
|
251
|
-
|
|
258
|
+
class PublicIPError < Error; end
|
|
259
|
+
|
|
260
|
+
# Instance of SPAroid that resolves its public IP once and reuses it
|
|
252
261
|
class Instance
|
|
253
262
|
include Sparoid
|
|
254
263
|
|
|
255
|
-
def
|
|
256
|
-
@
|
|
264
|
+
def initialize
|
|
265
|
+
@resolve_mutex = Mutex.new
|
|
266
|
+
@public_ips = []
|
|
257
267
|
end
|
|
258
268
|
|
|
259
269
|
def cached_public_ips
|
|
260
|
-
public_ips
|
|
270
|
+
return @public_ips if @public_ips.any?
|
|
271
|
+
|
|
272
|
+
@resolve_mutex.synchronize do
|
|
273
|
+
return @public_ips if @public_ips.any?
|
|
274
|
+
|
|
275
|
+
ips = public_ips
|
|
276
|
+
if ips.empty?
|
|
277
|
+
warn "Sparoid: Failed to retrieve public IPs"
|
|
278
|
+
else
|
|
279
|
+
@public_ips = ips
|
|
280
|
+
end
|
|
281
|
+
ips
|
|
282
|
+
end
|
|
261
283
|
end
|
|
262
284
|
end
|
|
263
285
|
end
|