fluent-plugin-secure-forward 0.0.3 → 0.0.4

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: 616e3ee6ce26495d3cae028b95f875452e65b281
4
- data.tar.gz: c2c1e3423af3a2659389b3ed3a534876b56ad9d3
3
+ metadata.gz: b51f31fdd96e025c02cc760ff62119649c41822b
4
+ data.tar.gz: 8e6173fe782e3fe9f1cb5f919c8f6eac6f43c455
5
5
  SHA512:
6
- metadata.gz: d33ca023780967c1d5e543dd30da3beea56c9cddc53ad43b346f19513fa72a00fb35c48797336910b6455de39b14e3e32212f4250073c28ede2d1fddbbfcc077
7
- data.tar.gz: 0353931f0f0308dc51719e24628cf96c9c01f53baba40ee087b5dd0f09f42c5bc7492475fe1434e15cc4706fbc0335f3728ca6f614b5a100fe98536bc332fb71
6
+ metadata.gz: f90bd6309c2b69c62133efe58fd7732c816c1256086ed681198dcc66d949095d3d3bc86fb78fc4e76ad7392ca1fe591d301bab6488a493aa81750eba266d76d1
7
+ data.tar.gz: ab9cef4259d0071e81fefbe389ffa4840a80bcc5f621f7b1e82bc79781b1278728c124807df925bec0ebfc4fc3e0405d5a6f98cae8331b864247fd6830d9b022
data/README.md CHANGED
@@ -126,7 +126,7 @@ Minimal configurations like this:
126
126
  </server>
127
127
  </match>
128
128
 
129
- At this version (v0.0.x), only one `<server>` section can be specified.
129
+ When specified 2 or more `<server>`, this plugin uses these nodes in simple round-robin order.
130
130
 
131
131
  If server requires username/password, set `username` and `password` in `<server>` section:
132
132
 
@@ -135,10 +135,15 @@ If server requires username/password, set `username` and `password` in `<server>
135
135
  shared_key secret_string
136
136
  self_hostname client.fqdn.local
137
137
  <server>
138
- host server.fqdn.local
138
+ host first.fqdn.local
139
139
  username repeatedly
140
140
  password sushi
141
141
  </server>
142
+ <server>
143
+ host second.fqdn.local
144
+ username sasatatsu
145
+ password karaage
146
+ </server>
142
147
  </match>
143
148
 
144
149
  ## Senario (developer document)
data/Rakefile CHANGED
@@ -1,2 +1,11 @@
1
1
  #!/usr/bin/env rake
2
2
  require "bundler/gem_tasks"
3
+
4
+ require 'rake/testtask'
5
+ Rake::TestTask.new(:test) do |test|
6
+ test.libs << 'lib' << 'test'
7
+ test.pattern = 'test/**/test_*.rb'
8
+ test.verbose = true
9
+ end
10
+
11
+ task :default => :test
data/example/client.conf CHANGED
@@ -9,5 +9,11 @@
9
9
  <server>
10
10
  host localhost
11
11
  </server>
12
+ <server>
13
+ host localhost
14
+ </server>
15
+ <server>
16
+ host localhost
17
+ </server>
12
18
  flush_interval 1s
13
19
  </match>
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  Gem::Specification.new do |gem|
3
3
  gem.name = "fluent-plugin-secure-forward"
4
- gem.version = "0.0.3"
4
+ gem.version = "0.0.4"
5
5
  gem.authors = ["TAGOMORI Satoshi"]
6
6
  gem.email = ["tagomoris@gmail.com"]
7
7
  gem.summary = %q{Fluentd input/output plugin to forward over SSL with authentications}
@@ -16,4 +16,5 @@ Gem::Specification.new do |gem|
16
16
  gem.add_runtime_dependency "fluentd"
17
17
  gem.add_runtime_dependency "fluent-mixin-config-placeholders"
18
18
  gem.add_runtime_dependency "resolve-hostname"
19
+ gem.add_development_dependency "rake"
19
20
  end
@@ -2,6 +2,13 @@
2
2
 
3
3
  require 'fluent/mixin/config_placeholders'
4
4
 
5
+ module Fluent
6
+ class SecureForwardInput < Input
7
+ end
8
+ end
9
+
10
+ require_relative 'input_session'
11
+
5
12
  module Fluent
6
13
  class SecureForwardInput < Input
7
14
  DEFAULT_SECURE_LISTEN_PORT = 24284
@@ -57,7 +64,6 @@ module Fluent
57
64
 
58
65
  def initialize
59
66
  super
60
- require 'resolv'
61
67
  require 'socket'
62
68
  require 'openssl'
63
69
  require 'digest'
@@ -214,210 +220,5 @@ module Fluent
214
220
  Fluent::Engine.emit(tag, time, record)
215
221
  end
216
222
  end
217
-
218
- class Session # Fluent::SecureForwardInput::Session
219
- attr_accessor :receiver
220
- attr_accessor :state, :thread, :node, :socket, :unpacker, :auth_salt
221
-
222
- def initialize(receiver, socket)
223
- @receiver = receiver
224
-
225
- @state = :helo
226
-
227
- @socket = socket
228
- @socket.sync = true
229
-
230
- @ipaddress = nil
231
- @node = nil
232
- @unpacker = MessagePack::Unpacker.new
233
- @thread = Thread.new(&method(:start))
234
- end
235
-
236
- def established?
237
- @state == :established
238
- end
239
-
240
- def generate_salt
241
- OpenSSL::Random.random_bytes(16)
242
- end
243
-
244
- def check_node(hostname, ipaddress, port, proto)
245
- node = nil
246
- family = Socket.const_get(proto)
247
- @receiver.nodes.each do |n|
248
- proto, port, host, ipaddr, family_num, socktype_num, proto_num = Socket.getaddrinfo(n[:host], port, family).first
249
- if ipaddr == ipaddress
250
- node = n
251
- break
252
- end
253
- end
254
- node
255
- end
256
-
257
- ## not implemented yet
258
- # def check_hostname_reverse_lookup(ipaddress)
259
- # rev_name = Resolv.getname(ipaddress)
260
- # proto, port, host, ipaddr, family_num, socktype_num, proto_num = Socket.getaddrinfo(rev_name, DUMMY_PORT)
261
- # unless ipaddr == ipaddress
262
- # return false
263
- # end
264
- # true
265
- # end
266
-
267
- def generate_helo
268
- $log.debug "generating helo"
269
- # ['HELO', options(hash)]
270
- [ 'HELO', {'auth' => (@receiver.authentication ? @auth_key_salt : ''), 'keepalive' => @receiver.allow_keepalive } ]
271
- end
272
-
273
- def check_ping(message)
274
- $log.debug "checking ping"
275
- # ['PING', self_hostname, shared_key\_salt, sha512\_hex(shared_key\_salt + self_hostname + shared_key),
276
- # username || '', sha512\_hex(auth\_salt + username + password) || '']
277
- unless message.size == 6 && message[0] == 'PING'
278
- return false, 'invalid ping message'
279
- end
280
- ping, hostname, shared_key_salt, shared_key_hexdigest, username, password_digest = message
281
-
282
- shared_key = if @node && @node[:shared_key]
283
- @node[:shared_key]
284
- else
285
- @receiver.shared_key
286
- end
287
- serverside = Digest::SHA512.new.update(shared_key_salt).update(hostname).update(shared_key).hexdigest
288
- if shared_key_hexdigest != serverside
289
- $log.warn "Shared key mismatch from '#{hostname}'"
290
- return false, 'shared_key mismatch'
291
- end
292
-
293
- if @receiver.authentication
294
- users = @receiver.select_authenticate_users(@node, username)
295
- success = false
296
- users.each do |user|
297
- passhash = Digest::SHA512.new.update(@auth_key_salt).update(username).update(user[:password]).hexdigest
298
- success ||= (passhash == password_digest)
299
- end
300
- unless success
301
- $log.warn "Authentication failed from client '#{hostname}', username '#{username}'"
302
- return false, 'username/password mismatch'
303
- end
304
- end
305
-
306
- return true, shared_key_salt
307
- end
308
-
309
- def generate_pong(auth_result, reason_or_salt)
310
- $log.debug "generating pong"
311
- # ['PONG', bool(authentication result), 'reason if authentication failed',
312
- # self_hostname, sha512\_hex(salt + self_hostname + sharedkey)]
313
- if not auth_result
314
- return ['PONG', false, reason_or_salt, '', '']
315
- end
316
-
317
- shared_key = if @node && @node[:shared_key]
318
- @node[:shared_key]
319
- else
320
- @receiver.shared_key
321
- end
322
- shared_key_hex = Digest::SHA512.new.update(reason_or_salt).update(@receiver.self_hostname).update(shared_key).hexdigest
323
- [ 'PONG', true, '', @receiver.self_hostname, shared_key_hex ]
324
- end
325
-
326
- def on_read(data)
327
- $log.debug "on_read"
328
- if self.established?
329
- @receiver.on_message(data)
330
- end
331
-
332
- case @state
333
- when :pingpong
334
- success, reason_or_salt = self.check_ping(data)
335
- if not success
336
- send_data generate_pong(false, reason_or_salt)
337
- self.shutdown
338
- return
339
- end
340
- send_data generate_pong(true, reason_or_salt)
341
-
342
- $log.debug "connection established"
343
- @state = :established
344
- end
345
- end
346
-
347
- def send_data(data)
348
- # not nonblock because write data (response) needs sequence
349
- @socket.write data.to_msgpack
350
- end
351
-
352
- def start
353
- $log.debug "starting server"
354
-
355
- $log.trace "accepting ssl session"
356
- begin
357
- @socket.accept
358
- rescue OpenSSL::SSL::SSLError => e
359
- $log.debug "failed to establish ssl session"
360
- self.shutdown
361
- return
362
- end
363
-
364
- proto, port, host, ipaddr = @socket.io.addr
365
- @node = check_node(host, ipaddr, port, proto)
366
- if @node.nil? && (! @receiver.allow_anonymous_source)
367
- $log.warn "Connection required from unknown host '#{host}' (#{ipaddr}), disconnecting..."
368
- self.shutdown
369
- return
370
- end
371
-
372
- @auth_key_salt = generate_salt
373
-
374
- buf = ''
375
- read_length = @receiver.read_length
376
- read_interval = @receiver.read_interval
377
- socket_interval = @receiver.socket_interval
378
-
379
- send_data generate_helo()
380
- @state = :pingpong
381
-
382
- loop do
383
- begin
384
- while @socket.read_nonblock(read_length, buf)
385
- if buf == ''
386
- sleep read_interval
387
- next
388
- end
389
- @unpacker.feed_each(buf, &method(:on_read))
390
- buf = ''
391
- end
392
- rescue OpenSSL::SSL::SSLError => e
393
- # to wait i/o restart
394
- sleep socket_interval
395
- rescue EOFError => e
396
- $log.debug "Connection closed from '#{host}'(#{ipaddr})"
397
- break
398
- end
399
- end
400
- rescue => e
401
- $log.warn e
402
- ensure
403
- self.shutdown
404
- end
405
-
406
- def shutdown
407
- @state = :closed
408
- if @thread == Thread.current
409
- @socket.close
410
- @thread.kill
411
- else
412
- if @thread
413
- @thread.kill
414
- @thread.join
415
- end
416
- @socket.close
417
- end
418
- rescue => e
419
- $log.debug "#{e.class}:#{e.message}"
420
- end
421
- end
422
223
  end
423
224
  end
@@ -0,0 +1,210 @@
1
+ # require 'msgpack'
2
+ # require 'socket'
3
+ # require 'openssl'
4
+ # require 'digest'
5
+ ### require 'resolv'
6
+
7
+ class Fluent::SecureForwardInput::Session
8
+ attr_accessor :receiver
9
+ attr_accessor :state, :thread, :node, :socket, :unpacker, :auth_salt
10
+
11
+ def initialize(receiver, socket)
12
+ @receiver = receiver
13
+
14
+ @state = :helo
15
+
16
+ @socket = socket
17
+ @socket.sync = true
18
+
19
+ @ipaddress = nil
20
+ @node = nil
21
+ @unpacker = MessagePack::Unpacker.new
22
+ @thread = Thread.new(&method(:start))
23
+ end
24
+
25
+ def established?
26
+ @state == :established
27
+ end
28
+
29
+ def generate_salt
30
+ OpenSSL::Random.random_bytes(16)
31
+ end
32
+
33
+ def check_node(hostname, ipaddress, port, proto)
34
+ node = nil
35
+ family = Socket.const_get(proto)
36
+ @receiver.nodes.each do |n|
37
+ proto, port, host, ipaddr, family_num, socktype_num, proto_num = Socket.getaddrinfo(n[:host], port, family).first
38
+ if ipaddr == ipaddress
39
+ node = n
40
+ break
41
+ end
42
+ end
43
+ node
44
+ end
45
+
46
+ ## not implemented yet
47
+ # def check_hostname_reverse_lookup(ipaddress)
48
+ # rev_name = Resolv.getname(ipaddress)
49
+ # proto, port, host, ipaddr, family_num, socktype_num, proto_num = Socket.getaddrinfo(rev_name, DUMMY_PORT)
50
+ # unless ipaddr == ipaddress
51
+ # return false
52
+ # end
53
+ # true
54
+ # end
55
+
56
+ def generate_helo
57
+ $log.debug "generating helo"
58
+ # ['HELO', options(hash)]
59
+ [ 'HELO', {'auth' => (@receiver.authentication ? @auth_key_salt : ''), 'keepalive' => @receiver.allow_keepalive } ]
60
+ end
61
+
62
+ def check_ping(message)
63
+ $log.debug "checking ping"
64
+ # ['PING', self_hostname, shared_key\_salt, sha512\_hex(shared_key\_salt + self_hostname + shared_key),
65
+ # username || '', sha512\_hex(auth\_salt + username + password) || '']
66
+ unless message.size == 6 && message[0] == 'PING'
67
+ return false, 'invalid ping message'
68
+ end
69
+ ping, hostname, shared_key_salt, shared_key_hexdigest, username, password_digest = message
70
+
71
+ shared_key = if @node && @node[:shared_key]
72
+ @node[:shared_key]
73
+ else
74
+ @receiver.shared_key
75
+ end
76
+ serverside = Digest::SHA512.new.update(shared_key_salt).update(hostname).update(shared_key).hexdigest
77
+ if shared_key_hexdigest != serverside
78
+ $log.warn "Shared key mismatch from '#{hostname}'"
79
+ return false, 'shared_key mismatch'
80
+ end
81
+
82
+ if @receiver.authentication
83
+ users = @receiver.select_authenticate_users(@node, username)
84
+ success = false
85
+ users.each do |user|
86
+ passhash = Digest::SHA512.new.update(@auth_key_salt).update(username).update(user[:password]).hexdigest
87
+ success ||= (passhash == password_digest)
88
+ end
89
+ unless success
90
+ $log.warn "Authentication failed from client '#{hostname}', username '#{username}'"
91
+ return false, 'username/password mismatch'
92
+ end
93
+ end
94
+
95
+ return true, shared_key_salt
96
+ end
97
+
98
+ def generate_pong(auth_result, reason_or_salt)
99
+ $log.debug "generating pong"
100
+ # ['PONG', bool(authentication result), 'reason if authentication failed',
101
+ # self_hostname, sha512\_hex(salt + self_hostname + sharedkey)]
102
+ if not auth_result
103
+ return ['PONG', false, reason_or_salt, '', '']
104
+ end
105
+
106
+ shared_key = if @node && @node[:shared_key]
107
+ @node[:shared_key]
108
+ else
109
+ @receiver.shared_key
110
+ end
111
+ shared_key_hex = Digest::SHA512.new.update(reason_or_salt).update(@receiver.self_hostname).update(shared_key).hexdigest
112
+ [ 'PONG', true, '', @receiver.self_hostname, shared_key_hex ]
113
+ end
114
+
115
+ def on_read(data)
116
+ $log.debug "on_read"
117
+ if self.established?
118
+ @receiver.on_message(data)
119
+ end
120
+
121
+ case @state
122
+ when :pingpong
123
+ success, reason_or_salt = self.check_ping(data)
124
+ if not success
125
+ send_data generate_pong(false, reason_or_salt)
126
+ self.shutdown
127
+ return
128
+ end
129
+ send_data generate_pong(true, reason_or_salt)
130
+
131
+ $log.debug "connection established"
132
+ @state = :established
133
+ end
134
+ end
135
+
136
+ def send_data(data)
137
+ # not nonblock because write data (response) needs sequence
138
+ @socket.write data.to_msgpack
139
+ end
140
+
141
+ def start
142
+ $log.debug "starting server"
143
+
144
+ $log.trace "accepting ssl session"
145
+ begin
146
+ @socket.accept
147
+ rescue OpenSSL::SSL::SSLError => e
148
+ $log.debug "failed to establish ssl session"
149
+ self.shutdown
150
+ return
151
+ end
152
+
153
+ proto, port, host, ipaddr = @socket.io.addr
154
+ @node = check_node(host, ipaddr, port, proto)
155
+ if @node.nil? && (! @receiver.allow_anonymous_source)
156
+ $log.warn "Connection required from unknown host '#{host}' (#{ipaddr}), disconnecting..."
157
+ self.shutdown
158
+ return
159
+ end
160
+
161
+ @auth_key_salt = generate_salt
162
+
163
+ buf = ''
164
+ read_length = @receiver.read_length
165
+ read_interval = @receiver.read_interval
166
+ socket_interval = @receiver.socket_interval
167
+
168
+ send_data generate_helo()
169
+ @state = :pingpong
170
+
171
+ loop do
172
+ begin
173
+ while @socket.read_nonblock(read_length, buf)
174
+ if buf == ''
175
+ sleep read_interval
176
+ next
177
+ end
178
+ @unpacker.feed_each(buf, &method(:on_read))
179
+ buf = ''
180
+ end
181
+ rescue OpenSSL::SSL::SSLError => e
182
+ # to wait i/o restart
183
+ sleep socket_interval
184
+ rescue EOFError => e
185
+ $log.debug "Connection closed from '#{host}'(#{ipaddr})"
186
+ break
187
+ end
188
+ end
189
+ rescue => e
190
+ $log.warn "unexpected error in in_secure_forward", :error_class => e.class, :error => e
191
+ ensure
192
+ self.shutdown
193
+ end
194
+
195
+ def shutdown
196
+ @state = :closed
197
+ if @thread == Thread.current
198
+ @socket.close
199
+ @thread.kill
200
+ else
201
+ if @thread
202
+ @thread.kill
203
+ @thread.join
204
+ end
205
+ @socket.close
206
+ end
207
+ rescue => e
208
+ $log.debug "#{e.class}:#{e.message}"
209
+ end
210
+ end
@@ -0,0 +1,38 @@
1
+ module Fluent::SecureForwardOutput::OpenSSLUtil
2
+ def self.verify_result_name(code)
3
+ case code
4
+ when OpenSSL::X509::V_OK then 'V_OK'
5
+ when OpenSSL::X509::V_ERR_AKID_SKID_MISMATCH then 'V_ERR_AKID_SKID_MISMATCH'
6
+ when OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION then 'V_ERR_APPLICATION_VERIFICATION'
7
+ when OpenSSL::X509::V_ERR_CERT_CHAIN_TOO_LONG then 'V_ERR_CERT_CHAIN_TOO_LONG'
8
+ when OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED then 'V_ERR_CERT_HAS_EXPIRED'
9
+ when OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID then 'V_ERR_CERT_NOT_YET_VALID'
10
+ when OpenSSL::X509::V_ERR_CERT_REJECTED then 'V_ERR_CERT_REJECTED'
11
+ when OpenSSL::X509::V_ERR_CERT_REVOKED then 'V_ERR_CERT_REVOKED'
12
+ when OpenSSL::X509::V_ERR_CERT_SIGNATURE_FAILURE then 'V_ERR_CERT_SIGNATURE_FAILURE'
13
+ when OpenSSL::X509::V_ERR_CERT_UNTRUSTED then 'V_ERR_CERT_UNTRUSTED'
14
+ when OpenSSL::X509::V_ERR_CRL_HAS_EXPIRED then 'V_ERR_CRL_HAS_EXPIRED'
15
+ when OpenSSL::X509::V_ERR_CRL_NOT_YET_VALID then 'V_ERR_CRL_NOT_YET_VALID'
16
+ when OpenSSL::X509::V_ERR_CRL_SIGNATURE_FAILURE then 'V_ERR_CRL_SIGNATURE_FAILURE'
17
+ when OpenSSL::X509::V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT then 'V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT'
18
+ when OpenSSL::X509::V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD then 'V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD'
19
+ when OpenSSL::X509::V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD then 'V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD'
20
+ when OpenSSL::X509::V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD then 'V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD'
21
+ when OpenSSL::X509::V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD then 'V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD'
22
+ when OpenSSL::X509::V_ERR_INVALID_CA then 'V_ERR_INVALID_CA'
23
+ when OpenSSL::X509::V_ERR_INVALID_PURPOSE then 'V_ERR_INVALID_PURPOSE'
24
+ when OpenSSL::X509::V_ERR_KEYUSAGE_NO_CERTSIGN then 'V_ERR_KEYUSAGE_NO_CERTSIGN'
25
+ when OpenSSL::X509::V_ERR_OUT_OF_MEM then 'V_ERR_OUT_OF_MEM'
26
+ when OpenSSL::X509::V_ERR_PATH_LENGTH_EXCEEDED then 'V_ERR_PATH_LENGTH_EXCEEDED'
27
+ when OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN then 'V_ERR_SELF_SIGNED_CERT_IN_CHAIN'
28
+ when OpenSSL::X509::V_ERR_SUBJECT_ISSUER_MISMATCH then 'V_ERR_SUBJECT_ISSUER_MISMATCH'
29
+ when OpenSSL::X509::V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY then 'V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY'
30
+ when OpenSSL::X509::V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE then 'V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY'
31
+ when OpenSSL::X509::V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE then 'V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE'
32
+ when OpenSSL::X509::V_ERR_UNABLE_TO_GET_CRL then 'V_ERR_UNABLE_TO_GET_CRL'
33
+ when OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT then 'V_ERR_UNABLE_TO_GET_ISSUER_CERT'
34
+ when OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY then 'V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY'
35
+ when OpenSSL::X509::V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE then 'V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE'
36
+ end
37
+ end
38
+ end
@@ -2,6 +2,13 @@
2
2
 
3
3
  require 'fluent/mixin/config_placeholders'
4
4
 
5
+ module Fluent
6
+ class SecureForwardOutput < ObjectBufferedOutput
7
+ end
8
+ end
9
+
10
+ require_relative 'output_node'
11
+
5
12
  module Fluent
6
13
  class SecureForwardOutput < ObjectBufferedOutput
7
14
  DEFAULT_SECURE_CONNECT_PORT = 24284
@@ -74,9 +81,8 @@ module Fluent
74
81
  raise Fluent::ConfigError, "unknown config tag name #{element.name}"
75
82
  end
76
83
  end
77
- if @nodes.size > 1
78
- raise Fluent::ConfigError, "Two or more servers are not supported yet."
79
- end
84
+ @next_node = 0
85
+ @mutex = Mutex.new
80
86
 
81
87
  @hostname_resolver = Resolve::Hostname.new(:system_resolver => true)
82
88
 
@@ -84,8 +90,21 @@ module Fluent
84
90
  end
85
91
 
86
92
  def select_node
87
- #TODO: roundrobin? random?
88
- @nodes.select(&:established?).first
93
+ tries = 0
94
+ nodes = @nodes.size
95
+ @mutex.synchronize {
96
+ n = nil
97
+ while tries <= nodes
98
+ n = @nodes[@next_node]
99
+ @next_node += 1
100
+ @next_node = 0 if @next_node >= nodes
101
+
102
+ return n if n && n.established?
103
+
104
+ tries += 1
105
+ end
106
+ nil
107
+ }
89
108
  end
90
109
 
91
110
  def start
@@ -168,266 +187,5 @@ module Fluent
168
187
  # writeRawBody(packed_es)
169
188
  es.write_to(ssl)
170
189
  end
171
-
172
- class Node # Fluent::SecureForwardOutput::Node
173
- attr_accessor :host, :port, :hostlabel, :shared_key, :username, :password
174
- attr_accessor :authentication, :keepalive
175
- attr_accessor :socket, :sslsession, :unpacker, :shared_key_salt, :state
176
-
177
- def initialize(sender, shared_key, conf)
178
- @sender = sender
179
- @shared_key = shared_key
180
-
181
- @host = conf['host']
182
- @port = (conf['port'] || DEFAULT_SECURE_CONNECT_PORT).to_i
183
- @hostlabel = conf['hostlabel'] || conf['host']
184
- @username = conf['username'] || ''
185
- @password = conf['password'] || ''
186
-
187
- @authentication = nil
188
- @keepalive = nil
189
-
190
- @socket = nil
191
- @sslsession = nil
192
- @unpacker = MessagePack::Unpacker.new
193
-
194
- @shared_key_salt = generate_salt
195
- @state = :helo
196
- @thread = nil
197
- end
198
-
199
- def dup
200
- Node.new(
201
- @sender,
202
- @shared_key,
203
- {'host' => @host, 'port' => @port, 'hostlabel' => @hostlabel, 'username' => @username, 'password' => @password}
204
- )
205
- end
206
-
207
- def start
208
- @thread = Thread.new(&method(:connect))
209
- end
210
-
211
- def shutdown
212
- $log.debug "shutting down node #{@host}"
213
- @state = :closed
214
-
215
- if @thread == Thread.current
216
- @sslsession.close if @sslsession
217
- @socket.close if @socket
218
- @thread.kill
219
- else
220
- if @thread
221
- @thread.kill
222
- @thread.join
223
- end
224
- @sslsession.close if @sslsession
225
- @socket.close if @socket
226
- end
227
- rescue => e
228
- $log.debug "error on node shutdown #{e.class}:#{e.message}"
229
- end
230
-
231
- def verify_result_name(code)
232
- case code
233
- when OpenSSL::X509::V_OK then 'V_OK'
234
- when OpenSSL::X509::V_ERR_AKID_SKID_MISMATCH then 'V_ERR_AKID_SKID_MISMATCH'
235
- when OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION then 'V_ERR_APPLICATION_VERIFICATION'
236
- when OpenSSL::X509::V_ERR_CERT_CHAIN_TOO_LONG then 'V_ERR_CERT_CHAIN_TOO_LONG'
237
- when OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED then 'V_ERR_CERT_HAS_EXPIRED'
238
- when OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID then 'V_ERR_CERT_NOT_YET_VALID'
239
- when OpenSSL::X509::V_ERR_CERT_REJECTED then 'V_ERR_CERT_REJECTED'
240
- when OpenSSL::X509::V_ERR_CERT_REVOKED then 'V_ERR_CERT_REVOKED'
241
- when OpenSSL::X509::V_ERR_CERT_SIGNATURE_FAILURE then 'V_ERR_CERT_SIGNATURE_FAILURE'
242
- when OpenSSL::X509::V_ERR_CERT_UNTRUSTED then 'V_ERR_CERT_UNTRUSTED'
243
- when OpenSSL::X509::V_ERR_CRL_HAS_EXPIRED then 'V_ERR_CRL_HAS_EXPIRED'
244
- when OpenSSL::X509::V_ERR_CRL_NOT_YET_VALID then 'V_ERR_CRL_NOT_YET_VALID'
245
- when OpenSSL::X509::V_ERR_CRL_SIGNATURE_FAILURE then 'V_ERR_CRL_SIGNATURE_FAILURE'
246
- when OpenSSL::X509::V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT then 'V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT'
247
- when OpenSSL::X509::V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD then 'V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD'
248
- when OpenSSL::X509::V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD then 'V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD'
249
- when OpenSSL::X509::V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD then 'V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD'
250
- when OpenSSL::X509::V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD then 'V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD'
251
- when OpenSSL::X509::V_ERR_INVALID_CA then 'V_ERR_INVALID_CA'
252
- when OpenSSL::X509::V_ERR_INVALID_PURPOSE then 'V_ERR_INVALID_PURPOSE'
253
- when OpenSSL::X509::V_ERR_KEYUSAGE_NO_CERTSIGN then 'V_ERR_KEYUSAGE_NO_CERTSIGN'
254
- when OpenSSL::X509::V_ERR_OUT_OF_MEM then 'V_ERR_OUT_OF_MEM'
255
- when OpenSSL::X509::V_ERR_PATH_LENGTH_EXCEEDED then 'V_ERR_PATH_LENGTH_EXCEEDED'
256
- when OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN then 'V_ERR_SELF_SIGNED_CERT_IN_CHAIN'
257
- when OpenSSL::X509::V_ERR_SUBJECT_ISSUER_MISMATCH then 'V_ERR_SUBJECT_ISSUER_MISMATCH'
258
- when OpenSSL::X509::V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY then 'V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY'
259
- when OpenSSL::X509::V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE then 'V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY'
260
- when OpenSSL::X509::V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE then 'V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE'
261
- when OpenSSL::X509::V_ERR_UNABLE_TO_GET_CRL then 'V_ERR_UNABLE_TO_GET_CRL'
262
- when OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT then 'V_ERR_UNABLE_TO_GET_ISSUER_CERT'
263
- when OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY then 'V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY'
264
- when OpenSSL::X509::V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE then 'V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE'
265
- end
266
- end
267
-
268
- def established?
269
- @state == :established
270
- end
271
-
272
- def generate_salt
273
- OpenSSL::Random.random_bytes(16)
274
- end
275
-
276
- def check_helo(message)
277
- $log.debug "checking helo"
278
- # ['HELO', options(hash)]
279
- unless message.size == 2 && message[0] == 'HELO'
280
- return false
281
- end
282
- opts = message[1]
283
- @authentication = opts['auth']
284
- @keepalive = opts['keepalive']
285
- true
286
- end
287
-
288
- def generate_ping
289
- $log.debug "generating ping"
290
- # ['PING', self_hostname, sharedkey\_salt, sha512\_hex(sharedkey\_salt + self_hostname + shared_key),
291
- # username || '', sha512\_hex(auth\_salt + username + password) || '']
292
- shared_key_hexdigest = Digest::SHA512.new.update(@shared_key_salt).update(@sender.self_hostname).update(@shared_key).hexdigest
293
- ping = ['PING', @sender.self_hostname, @shared_key_salt, shared_key_hexdigest]
294
- if @authentication != ''
295
- password_hexdigest = Digest::SHA512.new.update(@authentication).update(@username).update(@password).hexdigest
296
- ping.push(@username, password_hexdigest)
297
- else
298
- ping.push('','')
299
- end
300
- ping
301
- end
302
-
303
- def check_pong(message)
304
- $log.debug "checking pong"
305
- # ['PONG', bool(authentication result), 'reason if authentication failed',
306
- # self_hostname, sha512\_hex(salt + self_hostname + sharedkey)]
307
- unless message.size == 5 && message[0] == 'PONG'
308
- return false, 'invalid format for PONG message'
309
- end
310
- pong, auth_result, reason, hostname, shared_key_hexdigest = message
311
-
312
- unless auth_result
313
- return false, 'authentication failed: ' + reason
314
- end
315
-
316
- clientside = Digest::SHA512.new.update(@shared_key_salt).update(hostname).update(@shared_key).hexdigest
317
- unless shared_key_hexdigest == clientside
318
- return false, 'shared key mismatch'
319
- end
320
-
321
- return true, nil
322
- end
323
-
324
- def send_data(data)
325
- @sslsession.write data.to_msgpack
326
- end
327
-
328
- def on_read(data)
329
- $log.debug "on_read"
330
- if self.established?
331
- #TODO: ACK
332
- $log.warn "unknown packets arrived..."
333
- return
334
- end
335
-
336
- case @state
337
- when :helo
338
- # TODO: log debug
339
- unless check_helo(data)
340
- $log.warn "received invalid helo message from #{@host}"
341
- self.shutdown
342
- return
343
- end
344
- send_data generate_ping()
345
- @state = :pingpong
346
- when :pingpong
347
- success, reason = check_pong(data)
348
- unless success
349
- $log.warn "connection refused to #{@host}:" + reason
350
- self.shutdown
351
- return
352
- end
353
- $log.info "connection established to #{@host}"
354
- @state = :established
355
- end
356
- end
357
-
358
- def connect
359
- $log.debug "starting client"
360
-
361
- addr = @sender.hostname_resolver.getaddress(@host)
362
- $log.debug "create tcp socket to node", :host => @host, :address => addr, :port => @port
363
- sock = TCPSocket.new(addr, @port)
364
-
365
- $log.trace "changing socket options"
366
- opt = [1, @sender.send_timeout.to_i].pack('I!I!') # { int l_onoff; int l_linger; }
367
- sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, opt)
368
-
369
- opt = [@sender.send_timeout.to_i, 0].pack('L!L!') # struct timeval
370
- sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, opt)
371
-
372
- # TODO: SSLContext constructer parameter (SSL/TLS protocol version)
373
- $log.trace "initializing SSL contexts"
374
- context = OpenSSL::SSL::SSLContext.new
375
- # TODO: context.ca_file = (ca_file_path)
376
- # TODO: context.ciphers = (SSL Shared key chiper protocols)
377
-
378
- $log.debug "trying to connect ssl session", :host => @host, :ipaddr => addr, :port => @port
379
- sslsession = OpenSSL::SSL::SSLSocket.new(sock, context)
380
- # TODO: check connection failure
381
- sslsession.connect
382
- $log.debug "ssl session connected", :host => @host, :port => @port
383
-
384
- begin
385
- unless @sender.allow_self_signed_certificate
386
- $log.debug "checking peer's certificate", :subject => sslsession.peer_cert.subject
387
- sslsession.post_connection_check(@hostlabel)
388
- verify = sslsession.verify_result
389
- if verify != OpenSSL::X509::V_OK
390
- err_name = verify_result_name(verify)
391
- $log.warn "failed to verify certification while connecting host #{@host} as #{@hostlabel} (but not raised, why?)"
392
- $log.warn "verify_result: #{err_name}"
393
- raise RuntimeError, "failed to verify certification while connecting host #{@host} as #{@hostlabel}"
394
- end
395
- end
396
- rescue OpenSSL::SSL::SSLError => e
397
- $log.warn "failed to verify certification while connecting ssl session", :host => @host, :hostlabel => @hostlabel
398
- self.shutdown
399
- raise
400
- end
401
-
402
- $log.debug "ssl sessison connected", :host => @host, :port => @port
403
- @socket = sock
404
- @sslsession = sslsession
405
-
406
- buf = ''
407
- read_length = @sender.read_length
408
- read_interval = @sender.read_interval
409
- socket_interval = @sender.socket_interval
410
-
411
- loop do
412
- begin
413
- while @sslsession.read_nonblock(read_length, buf)
414
- if buf == ''
415
- sleep read_interval
416
- next
417
- end
418
- @unpacker.feed_each(buf, &method(:on_read))
419
- buf = ''
420
- end
421
- rescue OpenSSL::SSL::SSLError
422
- # to wait i/o restart
423
- sleep socket_interval
424
- rescue EOFError
425
- $log.warn "disconnected from #{@host}"
426
- break
427
- end
428
- end
429
- self.shutdown
430
- end
431
- end
432
190
  end
433
191
  end
@@ -0,0 +1,231 @@
1
+ # require 'msgpack'
2
+ # require 'socket'
3
+ # require 'openssl'
4
+ # require 'digest'
5
+ # require 'resolve/hostname'
6
+
7
+ require_relative 'openssl_util'
8
+
9
+ class Fluent::SecureForwardOutput::Node
10
+ attr_accessor :host, :port, :hostlabel, :shared_key, :username, :password
11
+ attr_accessor :authentication, :keepalive
12
+ attr_accessor :socket, :sslsession, :unpacker, :shared_key_salt, :state
13
+
14
+ def initialize(sender, shared_key, conf)
15
+ @sender = sender
16
+ @shared_key = shared_key
17
+
18
+ @host = conf['host']
19
+ @port = (conf['port'] || Fluent::SecureForwardOutput::DEFAULT_SECURE_CONNECT_PORT).to_i
20
+ @hostlabel = conf['hostlabel'] || conf['host']
21
+ @username = conf['username'] || ''
22
+ @password = conf['password'] || ''
23
+
24
+ @authentication = nil
25
+ @keepalive = nil
26
+
27
+ @socket = nil
28
+ @sslsession = nil
29
+ @unpacker = MessagePack::Unpacker.new
30
+
31
+ @shared_key_salt = generate_salt
32
+ @state = :helo
33
+ @thread = nil
34
+ end
35
+
36
+ def dup
37
+ self.class.new(
38
+ @sender,
39
+ @shared_key,
40
+ {'host' => @host, 'port' => @port, 'hostlabel' => @hostlabel, 'username' => @username, 'password' => @password}
41
+ )
42
+ end
43
+
44
+ def start
45
+ @thread = Thread.new(&method(:connect))
46
+ end
47
+
48
+ def shutdown
49
+ $log.debug "shutting down node #{@host}"
50
+ @state = :closed
51
+
52
+ if @thread == Thread.current
53
+ @sslsession.close if @sslsession
54
+ @socket.close if @socket
55
+ @thread.kill
56
+ else
57
+ if @thread
58
+ @thread.kill
59
+ @thread.join
60
+ end
61
+ @sslsession.close if @sslsession
62
+ @socket.close if @socket
63
+ end
64
+ rescue => e
65
+ $log.debug "error on node shutdown #{e.class}:#{e.message}"
66
+ end
67
+
68
+ def established?
69
+ @state == :established
70
+ end
71
+
72
+ def generate_salt
73
+ OpenSSL::Random.random_bytes(16)
74
+ end
75
+
76
+ def check_helo(message)
77
+ $log.debug "checking helo"
78
+ # ['HELO', options(hash)]
79
+ unless message.size == 2 && message[0] == 'HELO'
80
+ return false
81
+ end
82
+ opts = message[1]
83
+ @authentication = opts['auth']
84
+ @keepalive = opts['keepalive']
85
+ true
86
+ end
87
+
88
+ def generate_ping
89
+ $log.debug "generating ping"
90
+ # ['PING', self_hostname, sharedkey\_salt, sha512\_hex(sharedkey\_salt + self_hostname + shared_key),
91
+ # username || '', sha512\_hex(auth\_salt + username + password) || '']
92
+ shared_key_hexdigest = Digest::SHA512.new.update(@shared_key_salt).update(@sender.self_hostname).update(@shared_key).hexdigest
93
+ ping = ['PING', @sender.self_hostname, @shared_key_salt, shared_key_hexdigest]
94
+ if @authentication != ''
95
+ password_hexdigest = Digest::SHA512.new.update(@authentication).update(@username).update(@password).hexdigest
96
+ ping.push(@username, password_hexdigest)
97
+ else
98
+ ping.push('','')
99
+ end
100
+ ping
101
+ end
102
+
103
+ def check_pong(message)
104
+ $log.debug "checking pong"
105
+ # ['PONG', bool(authentication result), 'reason if authentication failed',
106
+ # self_hostname, sha512\_hex(salt + self_hostname + sharedkey)]
107
+ unless message.size == 5 && message[0] == 'PONG'
108
+ return false, 'invalid format for PONG message'
109
+ end
110
+ pong, auth_result, reason, hostname, shared_key_hexdigest = message
111
+
112
+ unless auth_result
113
+ return false, 'authentication failed: ' + reason
114
+ end
115
+
116
+ clientside = Digest::SHA512.new.update(@shared_key_salt).update(hostname).update(@shared_key).hexdigest
117
+ unless shared_key_hexdigest == clientside
118
+ return false, 'shared key mismatch'
119
+ end
120
+
121
+ return true, nil
122
+ end
123
+
124
+ def send_data(data)
125
+ @sslsession.write data.to_msgpack
126
+ end
127
+
128
+ def on_read(data)
129
+ $log.debug "on_read"
130
+ if self.established?
131
+ #TODO: ACK
132
+ $log.warn "unknown packets arrived..."
133
+ return
134
+ end
135
+
136
+ case @state
137
+ when :helo
138
+ # TODO: log debug
139
+ unless check_helo(data)
140
+ $log.warn "received invalid helo message from #{@host}"
141
+ self.shutdown
142
+ return
143
+ end
144
+ send_data generate_ping()
145
+ @state = :pingpong
146
+ when :pingpong
147
+ success, reason = check_pong(data)
148
+ unless success
149
+ $log.warn "connection refused to #{@host}:" + reason
150
+ self.shutdown
151
+ return
152
+ end
153
+ $log.info "connection established to #{@host}"
154
+ @state = :established
155
+ end
156
+ end
157
+
158
+ def connect
159
+ $log.debug "starting client"
160
+
161
+ addr = @sender.hostname_resolver.getaddress(@host)
162
+ $log.debug "create tcp socket to node", :host => @host, :address => addr, :port => @port
163
+ sock = TCPSocket.new(addr, @port)
164
+
165
+ $log.trace "changing socket options"
166
+ opt = [1, @sender.send_timeout.to_i].pack('I!I!') # { int l_onoff; int l_linger; }
167
+ sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, opt)
168
+
169
+ opt = [@sender.send_timeout.to_i, 0].pack('L!L!') # struct timeval
170
+ sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, opt)
171
+
172
+ # TODO: SSLContext constructer parameter (SSL/TLS protocol version)
173
+ $log.trace "initializing SSL contexts"
174
+ context = OpenSSL::SSL::SSLContext.new
175
+ # TODO: context.ca_file = (ca_file_path)
176
+ # TODO: context.ciphers = (SSL Shared key chiper protocols)
177
+
178
+ $log.debug "trying to connect ssl session", :host => @host, :ipaddr => addr, :port => @port
179
+ sslsession = OpenSSL::SSL::SSLSocket.new(sock, context)
180
+ # TODO: check connection failure
181
+ sslsession.connect
182
+ $log.debug "ssl session connected", :host => @host, :port => @port
183
+
184
+ begin
185
+ unless @sender.allow_self_signed_certificate
186
+ $log.debug "checking peer's certificate", :subject => sslsession.peer_cert.subject
187
+ sslsession.post_connection_check(@hostlabel)
188
+ verify = sslsession.verify_result
189
+ if verify != OpenSSL::X509::V_OK
190
+ err_name = Fluent::SecureForwardOutput::OpenSSLUtil.verify_result_name(verify)
191
+ $log.warn "failed to verify certification while connecting host #{@host} as #{@hostlabel} (but not raised, why?)"
192
+ $log.warn "verify_result: #{err_name}"
193
+ raise RuntimeError, "failed to verify certification while connecting host #{@host} as #{@hostlabel}"
194
+ end
195
+ end
196
+ rescue OpenSSL::SSL::SSLError => e
197
+ $log.warn "failed to verify certification while connecting ssl session", :host => @host, :hostlabel => @hostlabel
198
+ self.shutdown
199
+ raise
200
+ end
201
+
202
+ $log.debug "ssl sessison connected", :host => @host, :port => @port
203
+ @socket = sock
204
+ @sslsession = sslsession
205
+
206
+ buf = ''
207
+ read_length = @sender.read_length
208
+ read_interval = @sender.read_interval
209
+ socket_interval = @sender.socket_interval
210
+
211
+ loop do
212
+ begin
213
+ while @sslsession.read_nonblock(read_length, buf)
214
+ if buf == ''
215
+ sleep read_interval
216
+ next
217
+ end
218
+ @unpacker.feed_each(buf, &method(:on_read))
219
+ buf = ''
220
+ end
221
+ rescue OpenSSL::SSL::SSLError
222
+ # to wait i/o restart
223
+ sleep socket_interval
224
+ rescue EOFError
225
+ $log.warn "disconnected from #{@host}"
226
+ break
227
+ end
228
+ end
229
+ self.shutdown
230
+ end
231
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,29 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+
12
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
13
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
14
+ require 'fluent/test'
15
+ unless ENV.has_key?('VERBOSE')
16
+ nulllogger = Object.new
17
+ nulllogger.instance_eval {|obj|
18
+ def method_missing(method, *args)
19
+ # pass
20
+ end
21
+ }
22
+ $log = nulllogger
23
+ end
24
+
25
+ require 'fluent/plugin/in_secure_forward'
26
+ require 'fluent/plugin/out_secure_forward'
27
+
28
+ class Test::Unit::TestCase
29
+ end
@@ -0,0 +1,10 @@
1
+ require 'helper'
2
+
3
+ class SecureForwardInputTest < Test::Unit::TestCase
4
+ CONFIG = %[
5
+ ]
6
+
7
+ def create_driver(conf=CONFIG,tag='test')
8
+ Fluent::Test::InputTestDriver.new(Fluent::SecureForwardInput, tag).configure(conf)
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ require 'helper'
2
+
3
+ class SecureForwardOutputTest < Test::Unit::TestCase
4
+ CONFIG = %[
5
+ ]
6
+
7
+ def create_driver(conf=CONFIG,tag='test')
8
+ Fluent::Test::OutputTestDriver.new(Fluent::SecureForwardOutput, tag).configure(conf)
9
+ end
10
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-secure-forward
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - TAGOMORI Satoshi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-23 00:00:00.000000000 Z
11
+ date: 2013-07-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - '>='
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  description: This version is HIGHLY EXPERIMENTAL.
56
70
  email:
57
71
  - tagomoris@gmail.com
@@ -74,7 +88,11 @@ files:
74
88
  - example/server.conf
75
89
  - fluent-plugin-secure-forward.gemspec
76
90
  - lib/fluent/plugin/in_secure_forward.rb
91
+ - lib/fluent/plugin/input_session.rb
92
+ - lib/fluent/plugin/openssl_util.rb
77
93
  - lib/fluent/plugin/out_secure_forward.rb
94
+ - lib/fluent/plugin/output_node.rb
95
+ - test/helper.rb
78
96
  - test/plugin/test_in_secure_forward.rb
79
97
  - test/plugin/test_out_secure_forward.rb
80
98
  homepage: https://github.com/tagomoris/fluent-plugin-secure-forward
@@ -101,6 +119,7 @@ signing_key:
101
119
  specification_version: 4
102
120
  summary: Fluentd input/output plugin to forward over SSL with authentications
103
121
  test_files:
122
+ - test/helper.rb
104
123
  - test/plugin/test_in_secure_forward.rb
105
124
  - test/plugin/test_out_secure_forward.rb
106
125
  has_rdoc: