我在服務器監控程序ServerDog的Curl模塊中,使用curl命令來實現對一些網絡鏈接的監控。如:
curl -o /dev/null --connect-timeout 10 --max-time 50 -X GET -s -w http_code=%{http_code},ssl_verify_result=%{ssl_verify_result},time_namelooe_connect},time_appconnect=%{time_appconnect},time_redirect=%{time_redirect},num_redirects=%{num_redirects},time_pretransfer=%{time_pretransfer},time_starttransfer=%{time_starttransfer},time_total=%{time_total},size_download=%{size_download},speed_download=%{speed_download} https://src.xxx.com/dancen/curl.jpg
在開發階段,一切正常,當ServerDog部署到CentOS 7服務器以後,一堆報警就來了,curl無法訪問部分服務器,ServerDog認爲服務器出了故障,但實際上服務器是正常運行的。
爲了確認問題,直接在ServerDog所在服務器執行上面的curl命令,其返回結果爲:
http_code=000,ssl_verify_result=0,time_namelookup=0.000,time_connect=0.021,time_appconnect=0.281,time_redirect=0.281,num_redirects=0,time_pretransfer=0.000,time_starttransfer=0.000,time_total=0.281,size_download=0,speed_download=0.000
http_code爲000,不是我們一般所知道的200、3xx、4xx、5xx之類的狀態碼,而且命令是馬上執行完畢的,也就是說命令馬上就失敗了。
嘗試之
1. 直接在瀏覽器訪問域名https://src.xxx.com/dancen/curl.jpg,一切正常。
2. 在ServerDog的開發環境,一臺Windows上執行以上同樣的命令,返回結果也是正常:
http_code=200,ssl_verify_result=0,time_namelookup=0.028,time_connect=0.050,time_appconnect=0.202,time_redirect=0.000,num_redirects=0,time_pretransfer=0.202,time_starttransfer=0.228,time_total=0.399,size_download=1140931,speed_download=2856841.000
3. 在ServerDog所在服務器,將鏈接由原來的CDN鏈接
https://src.xxx.com/dancen/curl.jpg
修改爲直接訪問源服務器:
https://srccdn.xxx.com/dancen/curl.jpg
這次,命令的返回結果終於正常了。
4. 在ServerDog所在服務器,將鏈接
https://src.xxx.com/dancen/curl.jpg
中,https協議修改爲http協議(我們的服務器和CDN同時支持兩種協議):
http://src.xxx.com/dancen/curl.jpg
這次,命令的返回結果也是正常的。
基於以上幾點判斷,難道在Linux服務器上使用curl命令訪問帶有https協議的cdn站點有問題!!!不太可能呀~
5. 繼續嘗試,在公司的另外一臺Linux上,執行同樣的命令,返回結果也是正常的。這就說明,前邊的判斷錯誤,並不是在Linux上訪問基於cdn的https站點就會有問題。應該是cdn的節點上下載服務器的某些設定與ServerDog所在服務器有衝突。
調試之
1. 強制使用ipv4
curl -4
2. 強制使用特定版本的ssl
curl --tlsv1.1
問題依然存在:爲curl命令加上-v參數,將curl命令在ServerDog部署服務器上的執行過程打印出來看一下。
curl -o /dev/null --connect-timeout 10 --max-time 50 -X GET -s -w http_code=%{http_code},ssl_verify_result=%{ssl_verify_result},time_namelookup=%{time_namelookup},time_connect=%{time_connect},time_appconnect=%{time_appconnect},time_redirect=%{time_redirect},num_redirects=%{num_redirects},time_pretransfer=%{time_pretransfer},time_starttransfer=%{time_starttransfer},time_total=%{time_total},size_download=%{size_download},speed_download=%{speed_download} https://src.guangzhuiyuan.com/dancen/curl.jpg -v
輸出結果爲:
* About to connect() to src.guangzhuiyuan.com port 443 (#0)
* Trying 13.33.71.48...
* Connected to src.xxx.com (13.xx.71.xx) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* CAfile: /etc/pki/tls/certs/ca-bundle.crt
CApath: none
* NSS error -12190 (SSL_ERROR_PROTOCOL_VERSION_ALERT)
* Peer reports incompatible or unsupported protocol version.
* Error in TLS handshake, trying SSLv3...
> GET /dancen/curl.jpg HTTP/1.1
> User-Agent: curl/7.29.0
> Host: src.xxx.com
> Accept: */*
>
{ [data not shown]
* Connection died, retrying a fresh connect
* Closing connection 0
* Issue another request to this URL: 'https://src.xxx.com/dancen/curl.jpg'
* About to connect() to src.guangzhuiyuan.com port 443 (#1)
* Trying 13.xx.xx.xx...
* Connected to src.xxx.com (13.xx.xx.xx) port 443 (#1)
* TLS disabled due to previous handshake failure
* CAfile: /etc/pki/tls/certs/ca-bundle.crt
CApath: none
* NSS error -12286 (SSL_ERROR_NO_CYPHER_OVERLAP)
* Cannot communicate securely with peer: no common encryption algorithm(s).
* Closing connection 1
http_code=000,ssl_verify_result=0,time_namelookup=0.000,time_connect=0.021,time_appconnect=0.287,time_redirect=0.287,num_redirects=0,time_pretransfer=0.000,time_starttransfer=0.000,time_total=0.287,size_download=0,speed_download=0.000
看來是SSL錯誤:SSL_ERROR_PROTOCOL_VERSION_ALERT。由於ServerDog所在服務器使用了錯誤的SSL協議版本,與cdn節點服務器不兼容,因此連接被服務器直接拒絕,沒有產生實際的文件數據傳輸,所以正如前邊看到的一樣,命令很快就返回了錯誤結果。
解決辦法
升級ServerDog所在服務器的nss,curl:
yum update nss nss-util nspr
yum update curl