From 964570feba06594fc570ec4e08bfffe20f5ca805 Mon Sep 17 00:00:00 2001 From: Yann Coleu Date: Sun, 7 May 2017 23:34:39 +0200 Subject: [PATCH] 0.0.5 release --- README.md | 85 +++++++++++++++++++++++++++++++++++++++--------------- beeping.go | 48 +++++++++++++++++++++--------- 2 files changed, 97 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index fc9e7d0..c40b889 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# BeePing v0.4.0 +# BeePing v0.5.0 [![Build Status](https://travis-ci.org/yanc0/beeping.svg?branch=master)](https://travis-ci.org/yanc0/beeping) _previously named pingmeback_ @@ -23,6 +23,7 @@ Features: * Lot of metrics * Timeline of HTTP request * SSL Expiration check +* Server SSL/TLS version and Ciphers * Pattern check (search for text in response) * GeoIP resolution * Single binary @@ -44,16 +45,22 @@ Download latest version on [releases page](https://github.com/yanc0/beeping/rele $ ./beeping -h Usage of ./beeping: -geodatfile string - geoIP database path (default "/opt/GeoIP/GeoLite2-City.mmdb") + geoIP database path (default "/opt/GeoIP/GeoLite2-City.mmdb") -instance string - beeping instance name (default hostname) + beeping instance name (default hostname) + -listen string + The host to bind the server to (default "127.0.0.1") + -port string + The port to bind the server to (default "8080") + -tlsmode + Activate SSL/TLS versions and Cipher support checks (slow) ``` -beeping listens on 8080. You can choose the port by setting PORT env var +**Notes** -`PORT=3000 /usr/bin/beeping` - -If no GeoIP database is found, BeePing omit geo response silently +* If no GeoIP database is found, BeePing omit geo response silently +* TLSMode returns more infos on SSL object. It tries the more ciphers and TLS version + Golang can test but the checks can be way slower. ### Optional @@ -73,36 +80,59 @@ go build ## API Usage ``` -$ curl -XPOST http://localhost:8080/check -d '{"url": "https://google.fr", "pattern": "find me", "insecure": false, "timeout": 20} +$ curl -XPOST http://localhost:8080/check -d '{"url": "https://google.fr", "pattern": "find me", "header": "Server:GitHub.com", "insecure": false, "timeout": 20} { "http_status": "200 OK", "http_status_code": 200, "http_body_pattern": true, - "http_request_time": 119, + "http_header": true, + "http_request_time": 716, "instance_name": "X250", - "dns_lookup": 9, - "tcp_connection": 6, - "tls_handshake": 52, - "server_processing": 43, - "content_transfer": 6, + "dns_lookup": 14, + "tcp_connection": 101, + "tls_handshake": 228, + "server_processing": 168, + "content_transfer": 203, "timeline": { - "name_lookup": 9, - "connect": 16, - "pretransfer": 68, - "starttransfer": 112 + "name_lookup": 14, + "connect": 115, + "pretransfer": 344, + "starttransfer": 512 }, "geo": { "country": "US", - "ip": "216.58.209.227" + "ip": "192.30.253.112" }, - "ssl": true, - "ssl_expiry_date": "2017-07-05T13:28:00Z", - "ssl_days_left": 74 + "ssl": { + "ciphers": [ + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", + "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_RC4_128_SHA", + "TLS_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_RC4_128_SHA", + "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA" + ], + "protocol_versions": [ + "TLS12", + "TLS10", + "TLS11" + ], + "cert_expiry_date": "2018-05-17T12:00:00Z", + "cert_expiry_days_left": 374, + "cert_signature": "SHA256-RSA" + } } ``` * If pattern is not filled `http_body_pattern` is always `true` -* `tls_handshake`, `ssl_expiry_date` and `ssl_days_left` are not shown when `http://` only +* If header is not filled `http_header` is always `true` +* `ssl` is omitted when `http://`. The same for the `tls_handshake` field * `geo` is omitted if geoip is not set ## Error Handling @@ -117,6 +147,15 @@ beeping returns HTTP 500 when check fail. The body contains the reason of the fa ## Changelog +### 0.5.0 - 2017-05-07 + + * Add TLS Mode, now show server supported ciphers and SSL/TLS versions + * Add listen / Port options (**breaking change**) + * Modify JSON response structure (**breaking change**) + * Add proper logging + * Set proper User-Agent + * Add header check + ### 0.4.0 - 2017-04-24 * Pingmeback is now BeePing diff --git a/beeping.go b/beeping.go index 2b0dbc1..e18853f 100644 --- a/beeping.go +++ b/beeping.go @@ -17,8 +17,10 @@ import ( "time" ) -var VERSION = "0.4.0" +var VERSION = "0.5.0" var MESSAGE = "BeePing instance - HTTP Ping as a Service (github.com/yanc0/beeping)" +var USERAGENT = "Beeping " + VERSION + " - https://github.com/yanc0/beeping" + var geodatfile *string var instance *string var listen *string @@ -34,6 +36,7 @@ type Beeping struct { type Check struct { URL string `json:"url" binding:"required"` Pattern string `json:"pattern"` + Header string `json:"header"` Insecure bool `json:"insecure"` Timeout time.Duration `json:"timeout"` } @@ -56,6 +59,7 @@ type Response struct { HTTPStatus string `json:"http_status"` HTTPStatusCode int `json:"http_status_code"` HTTPBodyPattern bool `json:"http_body_pattern"` + HTTPHeader bool `json:"http_header"` HTTPRequestTime int64 `json:"http_request_time"` InstanceName string `json:"instance_name"` @@ -86,7 +90,7 @@ func main() { instance = flag.String("instance", "", "beeping instance name (default hostname)") listen = flag.String("listen", "127.0.0.1", "The host to bind the server to") port = flag.String("port", "8080", "The port to bind the server to") - tlsmode = flag.Bool("tlsmode", false, "Activate SSL/TLS versions and Cipher support checks") + tlsmode = flag.Bool("tlsmode", false, "Activate SSL/TLS versions and Cipher support checks (slow)") flag.Parse() gin.SetMode("release") @@ -134,6 +138,7 @@ func CheckHTTP(check *Check) (*Response, error) { return nil, err } + req.Header.Set("User-Agent", USERAGENT) // Create go-httpstat powered context and pass it to http.Request var result httpstat.Result ctx := httpstat.WithHTTPStat(req.Context(), &result) @@ -182,19 +187,28 @@ func CheckHTTP(check *Check) (*Response, error) { pattern = false } + header := true + if check.Header != "" { + key, value := splitCheckHeader(check.Header) + if key != "" && value != "" && res.Header.Get(key) != value { + header = false + } + } + response.HTTPStatus = res.Status response.HTTPStatusCode = res.StatusCode response.HTTPBodyPattern = pattern - response.HTTPRequestTime = Milliseconds(total) - response.Timeline.NameLookup = Milliseconds(result.NameLookup) - response.Timeline.Connect = Milliseconds(result.Connect) - response.Timeline.Pretransfer = Milliseconds(result.Pretransfer) - response.Timeline.StartTransfer = Milliseconds(result.StartTransfer) - response.DNSLookup = Milliseconds(result.DNSLookup) - response.TCPConnection = Milliseconds(result.TCPConnection) - response.TLSHandshake = Milliseconds(result.TLSHandshake) - response.ServerProcessing = Milliseconds(result.ServerProcessing) - response.ContentTransfer = Milliseconds(result.ContentTransfer(timeEndBody)) + response.HTTPHeader = header + response.HTTPRequestTime = milliseconds(total) + response.Timeline.NameLookup = milliseconds(result.NameLookup) + response.Timeline.Connect = milliseconds(result.Connect) + response.Timeline.Pretransfer = milliseconds(result.Pretransfer) + response.Timeline.StartTransfer = milliseconds(result.StartTransfer) + response.DNSLookup = milliseconds(result.DNSLookup) + response.TCPConnection = milliseconds(result.TCPConnection) + response.TLSHandshake = milliseconds(result.TLSHandshake) + response.ServerProcessing = milliseconds(result.ServerProcessing) + response.ContentTransfer = milliseconds(result.ContentTransfer(timeEndBody)) if res.TLS != nil { cTLS := &sslcheck.CheckSSL{} @@ -223,7 +237,7 @@ func CheckHTTP(check *Check) (*Response, error) { return response, nil } -func Milliseconds(d time.Duration) int64 { +func milliseconds(d time.Duration) int64 { return d.Nanoseconds() / 1000 / 1000 } @@ -260,3 +274,11 @@ func instanceName(name string, response *Response) error { return nil } + +func splitCheckHeader(header string) (string, string) { + h := strings.SplitN(header, ":", 2) + if len(h) == 2 { + return strings.TrimSpace(h[0]), strings.TrimSpace(h[1]) + } + return "", "" +} \ No newline at end of file