logstash-input-tcp 3.0.1 → 3.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|