class SyslogTls::SSLTransport
Supports SSL connection to remote host
Constants
- CONNECT_TIMEOUT
- WRITE_TIMEOUT
READ_TIMEOUT = 5
Attributes
ca_cert[R]
client_cert[R]
client_key[R]
host[R]
idle_timeout[R]
port[R]
retries[W]
socket[RW]
ssl_version[R]
verify_cert_name[R]
Public Class Methods
new(host, port, idle_timeout: nil, ca_cert: 'system', client_cert: nil, client_key: nil, verify_cert_name: true, ssl_version: :TLSv1_2, max_retries: 1)
click to toggle source
# File lib/syslog_tls/ssl_transport.rb, line 33 def initialize(host, port, idle_timeout: nil, ca_cert: 'system', client_cert: nil, client_key: nil, verify_cert_name: true, ssl_version: :TLSv1_2, max_retries: 1) @host = host @port = port @idle_timeout = idle_timeout @ca_cert = ca_cert @client_cert = client_cert @client_key = client_key @verify_cert_name = verify_cert_name @ssl_version = ssl_version @retries = max_retries connect end
Public Instance Methods
connect()
click to toggle source
# File lib/syslog_tls/ssl_transport.rb, line 46 def connect @socket = get_ssl_connection begin begin @socket.connect_nonblock rescue Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable select_with_timeout(@socket, :connect_read) && retry rescue IO::WaitWritable select_with_timeout(@socket, :connect_write) && retry end rescue Errno::ETIMEDOUT raise 'Socket timeout during connect' end @last_write = Time.now if idle_timeout end
do_write(data)
click to toggle source
# File lib/syslog_tls/ssl_transport.rb, line 150 def do_write(data) data.force_encoding('BINARY') # so we can break in the middle of multi-byte characters loop do sent = 0 begin sent = @socket.write_nonblock(data) rescue OpenSSL::SSL::SSLError, Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitWritable => e if e.is_a?(OpenSSL::SSL::SSLError) && e.message !~ /write would block/ raise e else select_with_timeout(@socket, :write) && retry end end break if sent >= data.size data = data[sent, data.size] end end
get_ssl_connection()
click to toggle source
# File lib/syslog_tls/ssl_transport.rb, line 95 def get_ssl_connection tcp = get_tcp_connection ctx = OpenSSL::SSL::SSLContext.new ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER ctx.ssl_version = ssl_version ctx.verify_hostname = verify_cert_name != false case ca_cert when true, 'true', 'system' # use system certs, same as openssl cli ctx.cert_store = OpenSSL::X509::Store.new ctx.cert_store.set_default_paths when false, 'false' ctx.verify_hostname = false ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE when %r{/$} # ends in / ctx.ca_path = ca_cert when String ctx.ca_file = ca_cert end ctx.cert = OpenSSL::X509::Certificate.new(File.read(client_cert)) if client_cert ctx.key = OpenSSL::PKey::read(File.read(client_key)) if client_key socket = OpenSSL::SSL::SSLSocket.new(tcp, ctx) socket.hostname = host socket.sync_close = true socket end
get_tcp_connection()
click to toggle source
# File lib/syslog_tls/ssl_transport.rb, line 62 def get_tcp_connection tcp = nil family = Socket::Constants::AF_UNSPEC sock_type = Socket::Constants::SOCK_STREAM addr_info = Socket.getaddrinfo(host, port, family, sock_type, nil, nil, false).first _, port, _, address, family, sock_type = addr_info begin sock_addr = Socket.sockaddr_in(port, address) tcp = Socket.new(family, sock_type, 0) tcp.setsockopt(Socket::SOL_SOCKET, Socket::Constants::SO_REUSEADDR, true) tcp.setsockopt(Socket::SOL_SOCKET, Socket::Constants::SO_REUSEPORT, true) tcp.connect_nonblock(sock_addr) rescue Errno::EINPROGRESS select_with_timeout(tcp, :connect_write) begin tcp.connect_nonblock(sock_addr) rescue Errno::EISCONN # all good rescue SystemCallError tcp.close rescue nil raise end rescue SystemCallError tcp.close rescue nil raise end tcp.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true) tcp end
method_missing(method_sym, *arguments, &block)
click to toggle source
Forward any methods directly to SSLSocket
# File lib/syslog_tls/ssl_transport.rb, line 186 def method_missing(method_sym, *arguments, &block) @socket.send(method_sym, *arguments, &block) end
select_with_timeout(tcp, type)
click to toggle source
# File lib/syslog_tls/ssl_transport.rb, line 169 def select_with_timeout(tcp, type) case type when :connect_read args = [[tcp], nil, nil, CONNECT_TIMEOUT] when :connect_write args = [nil, [tcp], nil, CONNECT_TIMEOUT] # when :read # args = [[tcp], nil, nil, READ_TIMEOUT] when :write args = [nil, [tcp], nil, WRITE_TIMEOUT] else raise "Unknown select type #{type}" end IO.select(*args) || raise("Socket timeout during #{type}") end
write(s)
click to toggle source
Allow to retry on failed writes
# File lib/syslog_tls/ssl_transport.rb, line 127 def write(s) if idle_timeout if (t=Time.now) > @last_write + idle_timeout @socket.close rescue nil connect else @last_write = t end end begin retry_id ||= 0 do_write(s) rescue => e if (retry_id += 1) < @retries @socket.close rescue nil connect retry else raise e end end end