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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d560100efd4b27bcef8c8865626a628de300b871
4
- data.tar.gz: 4f22528b91f54d136f838ae5ea7878c7df493462
3
+ metadata.gz: dfdbc6394d0429fde14caccd283662320d239396
4
+ data.tar.gz: 943b1ce9cb23f6b4d6ba0af1b72d935e7bf24b0e
5
5
  SHA512:
6
- metadata.gz: 28bd63a130f1fa48f9470800baea3bc2ea14c9541dd754886ed21428a184ffa2c060b2e12089172acf77297e3136ce471fb3337ce0664e276c7a41fdbf230192
7
- data.tar.gz: e03a18054310108f46336a10375d68dddfdcaba824102de882335aaa824634a05e4ae78357798f469a861e2ca79b144e9dfb642b88264480ee34b6036c84c300
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
 
@@ -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 => socket.peer)
162
+ @logger.debug? && @logger.debug("Connection closed", :client => peer)
163
163
  rescue Errno::ECONNRESET
164
- @logger.debug? && @logger.debug("Connection reset by peer", :client => socket.peer)
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 => socket.peer, :exception => e, :backtrace => e.backtrace)
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
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'logstash-input-tcp'
3
- s.version = '3.0.1'
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"
@@ -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
- let(:nevents) { 10 }
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
- describe "ssl" do
283
-
284
- let(:certificate) { helper.certificate }
285
-
286
- subject(:input) { LogStash::Plugin.lookup("input", "tcp").new(config) }
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" => "0.0.0.0",
263
+ "host" => "127.0.0.1",
291
264
  "port" => port,
292
- "ssl_verify" => false,
293
265
  "ssl_enable" => true,
294
- "ssl_cert" => certificate[0].path,
295
- "ssl_key" => certificate[1].path
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
- let(:events) do
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
- result
316
- end
277
+ before do
278
+ certificate_file.write(certificate)
279
+ key_file.write(key)
317
280
 
318
- it "should receive events" do
319
- expect(events.size).to be(nevents)
281
+ # Close to flush the file writes.
282
+ certificate_file.close
283
+ key_file.close
284
+ subject.register
320
285
  end
321
286
 
322
- it "should not contain sslsubject" do
323
- events.each do |event|
324
- expect(event["sslsubject"]).to be_nil
325
- end
287
+ after do
288
+ File.unlink(certificate_file.path)
289
+ File.unlink(key_file.path)
326
290
  end
327
291
 
328
- describe "when ssl_verify is on" do
292
+ context "with a poorly-behaving client" do
293
+ let!(:input_task) { Stud::Task.new { input.run(queue) } }
329
294
 
330
- let(:chain_of_certificates) { helper.chain_of_certificates }
295
+ after { input.close }
331
296
 
332
- let(:ssl_context) do
333
- ssl_context = OpenSSL::SSL::SSLContext.new
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
- OpenSSL::SSL::SSLSocket.new(client, ssl_context)
300
+ client.close
358
301
  end
359
302
 
360
- it "should raise an exception when connecting" do
361
- helper.pipelineless_input(subject, 0) do
362
- expect { socket.connect }.to raise_error
363
- socket.close rescue nil
364
- end
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 "and using the root CA" do
369
-
370
- let(:config) do
371
- {
372
- "host" => "0.0.0.0",
373
- "port" => port,
374
- "ssl_enable" => true,
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
- let(:events) do
386
- socket = Stud::try(5.times) do
387
- socket = TCPSocket.new("127.0.0.1", port)
388
- OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
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
- it "should contain sslsubject" do
409
- events.each do |event|
410
- expect(event["sslsubject"]).to eq("/DC=org/DC=ruby-lang/CN=RubyAA_Cert")
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 "using an extra chain of certificates" do
416
-
417
- let(:config) do
418
- {
419
- "host" => "0.0.0.0",
420
- "port" => port,
421
- "ssl_enable" => true,
422
- "ssl_verify" => true,
423
- "ssl_cert" => chain_of_certificates[:b_cert].path,
424
- "ssl_key" => chain_of_certificates[:b_key].path,
425
- "ssl_extra_chain_certs" => [ chain_of_certificates[:root_ca].path, chain_of_certificates[:a_cert].path, chain_of_certificates[:b_cert].path ]
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
- let(:client_certificate) { File.read(chain_of_certificates[:c_cert].path) }
430
- let(:client_key) { File.read(chain_of_certificates[:c_key].path) }
431
-
432
- let(:events) do
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
- it "should receive events" do
452
- expect(events.size).to be(nevents)
453
- end
363
+ # TODO(sissel): Spec multiple clients where only one is bad.
454
364
 
455
- it "should contain sslsubject" do
456
- events.each do |event|
457
- expect(event["sslsubject"]).to eq("/DC=org/DC=ruby-lang/CN=RubyC_Cert")
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.1
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-01-12 00:00:00.000000000 Z
11
+ date: 2016-02-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: logstash-core