Disable SNI Extension for Ruby net/http - Using IP

2019-08-09 01:15发布

问题:

I have a Ruby polling script that runs on a set of servers in an IP range. I very strongly prefer to do this polling by IP address, not by hostname, because:

1) I have defined IP address ranges to poll, and hostnames are arbitrary/change a lot

2) Because they change a lot, most of the hostnames do not have a reverse DNS lookup, so I can't engineer a list of hostnames from IPs

Before our web servers had no problem with this polling, but on a new server that does not accept SSLv3 communication, this is the error I get when I run my poll:

/home/dashboard/.rvm/rubies/ruby-2.1.6/lib/ruby/2.1.0/net/http.rb:923:in `connect': SSL_connect returned=1 errno=0 state=unknown state: tlsv1 unrecognized name (OpenSSL::SSL::SSLError)

On the server side, this is the error:

nss_engine_init.c(1802): start function ownSSLSNISocketConfig for SNI
nss_engine_init.c(1827): Search [val = 172.16.99.18] failed, unrecognized name

When I run the poll with hostname, everything works fine.

Here is the crux of the HTTP Client code in Ruby:

def init_http(url)
  uri = URI.parse(url)
  http = Net::HTTP.new(uri.host, uri.port)
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
  http.read_timeout = 10
  http.use_ssl = true
  #http.ssl_version = 'TLSv1'
  return [http, uri]
end

As you can tell, I've been playing around with TLS and SSL version, because I figured that might be the issue. My next thought (that Google only has evidence of for Java) is, "How easy is it to just disable the SNI extension on my client?" The more general question is, "Can I keep using IP addresses with Ruby net/http while taking advantage of newer, more secure communication protocols?"

回答1:

... tlsv1 unrecognized name (OpenSSL::SSL::SSLError)

This is in most cases not a problem you can solve by disabling SNI on the client side. SNI is required when you have multiple certificates on the same IP address and if you just connect by IP address and don't send the requested hostname (i.e. disabling SNI) the server will not know which certificate it should provide - which then results in the above error.

I very strongly prefer to do this polling by IP address, not by hostname, ...

If you have to deal with server which require SNI then you have to use SNI and you have to use SNI with the proper hostname, which is not necessarily the same name as you get from reverse lookup.



回答2:

The easiest way to solve this is to add the patch that @steffenullrich mentioned for bug 10613.

All I did was look at the diff, and edit the file myself, but you can use the Linux patch tool if you're familiar with it.

For those who are unsure of where /net/http.rb is located, it is in the same location as the rest of your Ruby sources. For example, mine was here:

/home/myuser/.rvm/rubies/ruby-2.1.6/lib/net/http.rb

Once you patch the file, set the .disable_sni property of your HTTP object to true, and SNI will not be required, allowing the use of IP addresses in mixed-TLS communication.