logstash-input-tcp 3.0.1 → 3.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/lib/logstash/inputs/tcp.rb +4 -4
- data/logstash-input-tcp.gemspec +1 -1
- data/spec/inputs/tcp_spec.rb +96 -183
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dfdbc6394d0429fde14caccd283662320d239396
|
4
|
+
data.tar.gz: 943b1ce9cb23f6b4d6ba0af1b72d935e7bf24b0e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e72fff4e6bc2b5e0d4929d8e9ab3552112cec606fba3040d08e12955b82a7b07c272a51d9b902be1cf5f8a1d84df74739994242703ee782eb0ca60f4b18e8d9
|
7
|
+
data.tar.gz: e49359fda655b9868540a91655e467f10d3e8c39383d3ef4c2ec8e95a2362b5ca5f26e2ee0f0c351ba0ae15378da246eb9d092da0a46aeceb44ad062bf8a16c5
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
## 3.0.2
|
2
|
+
- Fixed a bug where previous connection would accidentally be closed when accepting new socket connection
|
3
|
+
- Fixed an issue with log message which used a closed socket's peer address
|
4
|
+
|
1
5
|
## 3.0.1
|
2
6
|
- properly convert sslsubject to string before assigning to event field, added specs, see https://github.com/logstash-plugins/logstash-input-tcp/pull/38
|
3
7
|
|
data/lib/logstash/inputs/tcp.rb
CHANGED
@@ -115,7 +115,6 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
|
|
115
115
|
rescue OpenSSL::SSL::SSLError => e
|
116
116
|
# log error, close socket, accept next connection
|
117
117
|
@logger.error("SSL Error", :exception => e, :backtrace => e.backtrace)
|
118
|
-
socket.close rescue nil
|
119
118
|
rescue => e
|
120
119
|
# if this exception occured while the plugin is stopping
|
121
120
|
# just ignore and exit
|
@@ -149,6 +148,7 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
|
|
149
148
|
end
|
150
149
|
|
151
150
|
def handle_socket(socket, client_address, client_port, output_queue, codec)
|
151
|
+
peer = "#{client_address}:#{client_port}"
|
152
152
|
while !stop?
|
153
153
|
codec.decode(read(socket)) do |event|
|
154
154
|
event["host"] ||= client_address
|
@@ -159,16 +159,16 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
|
|
159
159
|
end
|
160
160
|
end
|
161
161
|
rescue EOFError
|
162
|
-
@logger.debug? && @logger.debug("Connection closed", :client =>
|
162
|
+
@logger.debug? && @logger.debug("Connection closed", :client => peer)
|
163
163
|
rescue Errno::ECONNRESET
|
164
|
-
@logger.debug? && @logger.debug("Connection reset by peer", :client =>
|
164
|
+
@logger.debug? && @logger.debug("Connection reset by peer", :client => peer)
|
165
165
|
rescue OpenSSL::SSL::SSLError => e
|
166
166
|
# Fixes issue #23
|
167
167
|
@logger.error("SSL Error", :exception => e, :backtrace => e.backtrace)
|
168
168
|
socket.close rescue nil
|
169
169
|
rescue => e
|
170
170
|
# if plugin is stopping, don't bother logging it as an error
|
171
|
-
!stop? && @logger.error("An error occurred. Closing connection", :client =>
|
171
|
+
!stop? && @logger.error("An error occurred. Closing connection", :client => peer, :exception => e, :backtrace => e.backtrace)
|
172
172
|
ensure
|
173
173
|
# catch all rescue nil on close to discard any close errors or invalid socket
|
174
174
|
socket.close rescue nil
|
data/logstash-input-tcp.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'logstash-input-tcp'
|
3
|
-
s.version = '3.0.
|
3
|
+
s.version = '3.0.2'
|
4
4
|
s.licenses = ['Apache License (2.0)']
|
5
5
|
s.summary = "Read events over a TCP socket."
|
6
6
|
s.description = "This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program"
|
data/spec/inputs/tcp_spec.rb
CHANGED
@@ -5,11 +5,14 @@ require "timeout"
|
|
5
5
|
require "logstash/json"
|
6
6
|
require "logstash/inputs/tcp"
|
7
7
|
require "stud/try"
|
8
|
+
require "stud/task"
|
8
9
|
require "flores/pki"
|
9
10
|
require "openssl"
|
10
11
|
|
11
12
|
require_relative "../spec_helper"
|
12
13
|
|
14
|
+
#Cabin::Channel.get(LogStash).subscribe(STDOUT)
|
15
|
+
#Cabin::Channel.get(LogStash).level = :debug
|
13
16
|
describe LogStash::Inputs::Tcp do
|
14
17
|
|
15
18
|
context "codec (PR #1372)" do
|
@@ -236,229 +239,139 @@ describe LogStash::Inputs::Tcp do
|
|
236
239
|
subject.close rescue nil
|
237
240
|
end
|
238
241
|
|
239
|
-
describe "register" do
|
242
|
+
describe "#register" do
|
240
243
|
it "should register without errors" do
|
241
244
|
expect { subject.register }.to_not raise_error
|
242
245
|
end
|
243
246
|
end
|
244
247
|
|
245
|
-
describe "receive" do
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
let(:events) do
|
250
|
-
socket = Stud::try(5.times) { TCPSocket.new("127.0.0.1", port) }
|
251
|
-
|
252
|
-
result = helper.pipelineless_input(subject, nevents) do
|
253
|
-
nevents.times do |i|
|
254
|
-
socket.puts("msg #{i}")
|
255
|
-
socket.flush
|
256
|
-
end
|
257
|
-
end
|
258
|
-
socket.close rescue nil
|
259
|
-
|
260
|
-
result
|
261
|
-
end
|
262
|
-
|
263
|
-
before(:each) do
|
264
|
-
subject.register
|
265
|
-
end
|
266
|
-
|
267
|
-
it "should receive events been generated" do
|
268
|
-
expect(events.size).to be(nevents)
|
269
|
-
messages = events.map { |event| event["message"]}
|
270
|
-
messages.each do |message|
|
271
|
-
expect(message).to match(/msg \d+/)
|
272
|
-
end
|
273
|
-
end
|
274
|
-
|
275
|
-
it "should add the host and port to the generated event" do
|
276
|
-
events.each do |event|
|
277
|
-
expect(event["host"]).to eq("127.0.0.1")
|
278
|
-
expect(event["port"]).to be_an(Fixnum)
|
279
|
-
end
|
248
|
+
describe "#receive" do
|
249
|
+
shared_examples "receiving events" do
|
250
|
+
# TODO(sissel): Implement normal event-receipt tests as as a shared example
|
280
251
|
end
|
281
252
|
|
282
|
-
|
283
|
-
|
284
|
-
let(:certificate) {
|
285
|
-
|
286
|
-
|
253
|
+
context "when ssl_enable is true" do
|
254
|
+
let(:pki) { Flores::PKI.generate }
|
255
|
+
let(:certificate) { pki[0] }
|
256
|
+
let(:key) { pki[1] }
|
257
|
+
let(:certificate_file) { Stud::Temporary.file }
|
258
|
+
let(:key_file) { Stud::Temporary.file }
|
259
|
+
let(:queue) { Queue.new }
|
287
260
|
|
288
261
|
let(:config) do
|
289
262
|
{
|
290
|
-
"host" => "
|
263
|
+
"host" => "127.0.0.1",
|
291
264
|
"port" => port,
|
292
|
-
"ssl_verify" => false,
|
293
265
|
"ssl_enable" => true,
|
294
|
-
"ssl_cert" =>
|
295
|
-
"ssl_key" =>
|
266
|
+
"ssl_cert" => certificate_file.path,
|
267
|
+
"ssl_key" => key_file.path,
|
268
|
+
|
269
|
+
# Trust our self-signed cert.
|
270
|
+
# TODO(sissel): Make this a separate certificate for the client
|
271
|
+
"ssl_extra_chain_certs" => certificate_file.path
|
296
272
|
}
|
297
273
|
end
|
298
274
|
|
299
|
-
|
300
|
-
socket = Stud::try(5.times) do
|
301
|
-
ssl_context = OpenSSL::SSL::SSLContext.new
|
302
|
-
socket = TCPSocket.new("127.0.0.1", port)
|
303
|
-
OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
|
304
|
-
end
|
305
|
-
|
306
|
-
result = helper.pipelineless_input(subject, nevents) do
|
307
|
-
socket.connect
|
308
|
-
nevents.times do |i|
|
309
|
-
socket.puts("msg #{i}")
|
310
|
-
socket.flush
|
311
|
-
end
|
312
|
-
end
|
313
|
-
socket.close rescue nil
|
275
|
+
subject(:input) { LogStash::Plugin.lookup("input", "tcp").new(config) }
|
314
276
|
|
315
|
-
|
316
|
-
|
277
|
+
before do
|
278
|
+
certificate_file.write(certificate)
|
279
|
+
key_file.write(key)
|
317
280
|
|
318
|
-
|
319
|
-
|
281
|
+
# Close to flush the file writes.
|
282
|
+
certificate_file.close
|
283
|
+
key_file.close
|
284
|
+
subject.register
|
320
285
|
end
|
321
286
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
end
|
287
|
+
after do
|
288
|
+
File.unlink(certificate_file.path)
|
289
|
+
File.unlink(key_file.path)
|
326
290
|
end
|
327
291
|
|
328
|
-
|
292
|
+
context "with a poorly-behaving client" do
|
293
|
+
let!(:input_task) { Stud::Task.new { input.run(queue) } }
|
329
294
|
|
330
|
-
|
295
|
+
after { input.close }
|
331
296
|
|
332
|
-
|
333
|
-
|
334
|
-
ssl_context.cert = OpenSSL::X509::Certificate.new(client_certificate)
|
335
|
-
ssl_context.key = OpenSSL::PKey::RSA.new(client_key)
|
336
|
-
ssl_context
|
337
|
-
end
|
338
|
-
|
339
|
-
context "and the verification fails" do
|
340
|
-
|
341
|
-
let(:config) do
|
342
|
-
{
|
343
|
-
"host" => "0.0.0.0",
|
344
|
-
"port" => port,
|
345
|
-
"ssl_enable" => true,
|
346
|
-
"ssl_verify" => true,
|
347
|
-
"ssl_cert" => chain_of_certificates[:a_cert].path,
|
348
|
-
"ssl_key" => chain_of_certificates[:a_key].path
|
349
|
-
}
|
350
|
-
end
|
351
|
-
|
352
|
-
let(:client_certificate) { File.read(chain_of_certificates[:b_cert].path) }
|
353
|
-
let(:client_key) { File.read(chain_of_certificates[:b_key].path) }
|
354
|
-
|
355
|
-
let(:socket) do
|
297
|
+
context "that disconnects before doing TLS handshake" do
|
298
|
+
before do
|
356
299
|
client = TCPSocket.new("127.0.0.1", port)
|
357
|
-
|
300
|
+
client.close
|
358
301
|
end
|
359
302
|
|
360
|
-
it "should
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
303
|
+
it "should not negatively impact the plugin" do
|
304
|
+
# TODO(sissel): Look for a better way to detect this failure
|
305
|
+
# besides a sleep/wait.
|
306
|
+
result = input_task.thread.join(0.5)
|
307
|
+
expect(result).to be_nil
|
365
308
|
end
|
366
309
|
end
|
367
310
|
|
368
|
-
context "
|
369
|
-
|
370
|
-
let(:
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
"ssl_verify" => true,
|
376
|
-
"ssl_cert" => chain_of_certificates[:a_cert].path,
|
377
|
-
"ssl_key" => chain_of_certificates[:a_key].path,
|
378
|
-
"ssl_cacert" => chain_of_certificates[:root_ca].path
|
379
|
-
}
|
380
|
-
end
|
381
|
-
|
382
|
-
let(:client_certificate) { File.read(chain_of_certificates[:aa_cert].path) }
|
383
|
-
let(:client_key) { File.read(chain_of_certificates[:aa_key].path) }
|
311
|
+
context "that sends garbage instead of TLS handshake" do
|
312
|
+
let!(:input_task) { Stud::Task.new { input.run(queue) } }
|
313
|
+
let(:max_length) { 1000 }
|
314
|
+
let(:garbage) { Flores::Random.iterations(max_length).collect { Flores::Random.integer(1...255) }.pack("C*") }
|
315
|
+
before do
|
316
|
+
# Assertion to verify this test is actually sending something.
|
317
|
+
expect(garbage.length).to be > 0
|
384
318
|
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
end
|
390
|
-
|
391
|
-
result = helper.pipelineless_input(subject, nevents) do
|
392
|
-
socket.connect
|
393
|
-
nevents.times do |i|
|
394
|
-
socket.puts("msg #{i}")
|
395
|
-
socket.flush
|
396
|
-
end
|
397
|
-
end
|
398
|
-
|
399
|
-
socket.close rescue nil
|
400
|
-
|
401
|
-
result
|
402
|
-
end
|
403
|
-
|
404
|
-
it "should receive events" do
|
405
|
-
expect(events.size).to be(nevents)
|
319
|
+
client = TCPSocket.new("127.0.0.1", port)
|
320
|
+
client.write(garbage)
|
321
|
+
client.flush
|
322
|
+
Thread.new { sleep(1); client.close }
|
406
323
|
end
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
end
|
324
|
+
it "should not negatively impact the plugin" do
|
325
|
+
# TODO(sissel): Look for a better way to detect this failure besides a sleep/wait.
|
326
|
+
result = input_task.thread.join(0.5)
|
327
|
+
expect(result).to be_nil
|
412
328
|
end
|
413
329
|
end
|
414
330
|
|
415
|
-
context "
|
416
|
-
|
417
|
-
let(:
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
331
|
+
context "connection was healthy but now has garbage or corruption" do
|
332
|
+
let!(:input_task) { Stud::Task.new { input.run(queue) } }
|
333
|
+
let(:tcp) { TCPSocket.new("127.0.0.1", port) }
|
334
|
+
let(:sslcontext) { OpenSSL::SSL::SSLContext.new }
|
335
|
+
let(:sslsocket) { OpenSSL::SSL::SSLSocket.new(tcp, sslcontext) }
|
336
|
+
let(:max_length) { 1000 }
|
337
|
+
let(:garbage) { Flores::Random.iterations(max_length).collect { Flores::Random.integer(1...255) }.pack("C*") }
|
338
|
+
|
339
|
+
before do
|
340
|
+
sslcontext.cert = certificate
|
341
|
+
sslcontext.key = key
|
342
|
+
sslcontext.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
343
|
+
|
344
|
+
sslsocket.connect
|
345
|
+
sslsocket.write("Hello world\n")
|
346
|
+
|
347
|
+
# Assertion to verify this test is actually sending something.
|
348
|
+
expect(garbage.length).to be > 0
|
349
|
+
tcp.write(garbage)
|
350
|
+
tcp.flush
|
351
|
+
sslsocket.close
|
352
|
+
tcp.close
|
427
353
|
end
|
428
354
|
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
socket = Stud::try(5.times) do
|
434
|
-
socket = TCPSocket.new("127.0.0.1", port)
|
435
|
-
OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
|
436
|
-
end
|
437
|
-
|
438
|
-
result = helper.pipelineless_input(subject, nevents) do
|
439
|
-
socket.connect
|
440
|
-
nevents.times do |i|
|
441
|
-
socket.puts("msg #{i}")
|
442
|
-
socket.flush
|
443
|
-
end
|
444
|
-
end
|
445
|
-
|
446
|
-
socket.close rescue nil
|
447
|
-
|
448
|
-
result
|
355
|
+
it "should not negatively impact the plugin" do
|
356
|
+
# TODO(sissel): Look for a better way to detect this failure besides a sleep/wait.
|
357
|
+
result = input_task.thread.join(0.5)
|
358
|
+
expect(result).to be_nil
|
449
359
|
end
|
360
|
+
end
|
361
|
+
end
|
450
362
|
|
451
|
-
|
452
|
-
expect(events.size).to be(nevents)
|
453
|
-
end
|
363
|
+
# TODO(sissel): Spec multiple clients where only one is bad.
|
454
364
|
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
end
|
459
|
-
end
|
460
|
-
end
|
365
|
+
context "with client certificate problems" do
|
366
|
+
context "using an expired certificate"
|
367
|
+
context "using an untrusted certificate"
|
461
368
|
end
|
369
|
+
|
370
|
+
context "with a good connection" do
|
371
|
+
# TODO(sissel): use shared example
|
372
|
+
include_examples "receiving events"
|
373
|
+
end
|
374
|
+
|
462
375
|
end
|
463
376
|
end
|
464
377
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-input-tcp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Elastic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-02-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: logstash-core
|