Skip to content

Instantly share code, notes, and snippets.

@karlentwistle
Created April 14, 2014 18:36
Show Gist options
  • Save karlentwistle/10672488 to your computer and use it in GitHub Desktop.
Save karlentwistle/10672488 to your computer and use it in GitHub Desktop.
ssh doctor
# Usage: ruby doctor.rb [HOST=status.github.com[:PORT=443]]
require 'rbconfig'
require 'net/https'
if ARGV[0] =~ /^[^-]/
host, port = ARGV[0].split(':', 2)
else
host = 'status.github.com'
end
port ||= 443
ruby = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'])
ruby_version = RUBY_VERSION
if patch = RbConfig::CONFIG['PATCHLEVEL']
ruby_version += "-p#{patch}"
end
puts "%s (%s)" % [ruby, ruby_version]
openssl_dir = OpenSSL::X509::DEFAULT_CERT_AREA
mac_openssl = '/System/Library/OpenSSL' == openssl_dir
puts "%s: %s" % [OpenSSL::OPENSSL_VERSION, openssl_dir]
[OpenSSL::X509::DEFAULT_CERT_DIR_ENV, OpenSSL::X509::DEFAULT_CERT_FILE_ENV].each do |key|
puts "%s=%s" % [key, ENV[key].to_s.inspect]
end
ca_file = ENV[OpenSSL::X509::DEFAULT_CERT_FILE_ENV] || OpenSSL::X509::DEFAULT_CERT_FILE
ca_path = (ENV[OpenSSL::X509::DEFAULT_CERT_DIR_ENV] || OpenSSL::X509::DEFAULT_CERT_DIR).chomp('/')
puts "\nHEAD https://#{host}:#{port}"
http = Net::HTTP.new(host, port)
http.use_ssl = true
# Explicitly setting cert_store like this is not needed in most cases but it
# seems necessary in edge cases such as when using `verify_callback` in some
# combination of Ruby + OpenSSL versions.
http.cert_store = OpenSSL::X509::Store.new
http.cert_store.set_default_paths
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
failed_cert = failed_cert_reason = nil
if mac_openssl
warn "warning: will not be able show failed certificate info on OS X's OpenSSL"
# This drives me absolutely nuts. It seems that on Rubies compiled against OS X's
# system OpenSSL, the mere fact of defining a `verify_callback` makes the
# cert verification fail for requests that would otherwise be successful.
else
http.verify_callback = lambda { |verify_ok, store_context|
if !verify_ok
failed_cert = store_context.current_cert
failed_cert_reason = "%d: %s" % [ store_context.error, store_context.error_string ]
end
verify_ok
}
end
user_agent = "net/http #{ruby_version}"
req = Net::HTTP::Head.new('/', 'user-agent' => user_agent)
begin
res = http.start { http.request(req) }
abort res.inspect if res.code.to_i >= 500
puts "OK"
rescue Errno::ECONNREFUSED
puts "Error: connection refused"
exit 1
rescue OpenSSL::SSL::SSLError => e
puts "#{e.class}: #{e.message}"
if failed_cert
puts "\nThe server presented a certificate that could not be verified:"
puts " subject: #{failed_cert.subject}"
puts " issuer: #{failed_cert.issuer}"
puts " error code %s" % failed_cert_reason
end
ca_file_missing = !File.exist?(ca_file) && !mac_openssl
ca_path_empty = Dir["#{ca_path}/*"].empty?
if ca_file_missing || ca_path_empty
puts "\nPossible causes:"
puts " `%s' does not exist" % ca_file if ca_file_missing
puts " `%s/' is empty" % ca_path if ca_path_empty
end
exit 1
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment