connectivity.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. package scan
  2. import (
  3. "bufio"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "net"
  8. "github.com/cloudflare/cfssl/scan/crypto/tls"
  9. )
  10. // Connectivity contains scanners testing basic connectivity to the host
  11. var Connectivity = &Family{
  12. Description: "Scans for basic connectivity with the host through DNS and TCP/TLS dials",
  13. Scanners: map[string]*Scanner{
  14. "DNSLookup": {
  15. "Host can be resolved through DNS",
  16. dnsLookupScan,
  17. },
  18. "CloudFlareStatus": {
  19. "Host is on CloudFlare",
  20. onCloudFlareScan,
  21. },
  22. "TCPDial": {
  23. "Host accepts TCP connection",
  24. tcpDialScan,
  25. },
  26. "TLSDial": {
  27. "Host can perform TLS handshake",
  28. tlsDialScan,
  29. },
  30. },
  31. }
  32. // dnsLookupScan tests that DNS resolution of the host returns at least one address
  33. func dnsLookupScan(addr, hostname string) (grade Grade, output Output, err error) {
  34. addrs, err := net.LookupHost(hostname)
  35. if err != nil {
  36. return
  37. }
  38. if len(addrs) == 0 {
  39. err = errors.New("no addresses found for host")
  40. }
  41. grade, output = Good, addrs
  42. return
  43. }
  44. var (
  45. cfNets []*net.IPNet
  46. cfNetsErr error
  47. )
  48. func initOnCloudFlareScan() ([]*net.IPNet, error) {
  49. // Propagate previous errors and don't attempt to re-download.
  50. if cfNetsErr != nil {
  51. return nil, cfNetsErr
  52. }
  53. // Don't re-download ranges if we already have them.
  54. if len(cfNets) > 0 {
  55. return cfNets, nil
  56. }
  57. // Download CloudFlare CIDR ranges and parse them.
  58. v4resp, err := Client.Get("https://www.cloudflare.com/ips-v4")
  59. if err != nil {
  60. cfNetsErr = fmt.Errorf("Couldn't download CloudFlare IPs: %v", err)
  61. return nil, cfNetsErr
  62. }
  63. defer v4resp.Body.Close()
  64. v6resp, err := Client.Get("https://www.cloudflare.com/ips-v6")
  65. if err != nil {
  66. cfNetsErr = fmt.Errorf("Couldn't download CloudFlare IPs: %v", err)
  67. return nil, cfNetsErr
  68. }
  69. defer v6resp.Body.Close()
  70. scanner := bufio.NewScanner(io.MultiReader(v4resp.Body, v6resp.Body))
  71. for scanner.Scan() {
  72. _, ipnet, err := net.ParseCIDR(scanner.Text())
  73. if err != nil {
  74. cfNetsErr = fmt.Errorf("Couldn't parse CIDR range: %v", err)
  75. return nil, cfNetsErr
  76. }
  77. cfNets = append(cfNets, ipnet)
  78. }
  79. if err := scanner.Err(); err != nil {
  80. cfNetsErr = fmt.Errorf("Couldn't read IP bodies: %v", err)
  81. return nil, cfNetsErr
  82. }
  83. return cfNets, nil
  84. }
  85. func onCloudFlareScan(addr, hostname string) (grade Grade, output Output, err error) {
  86. var cloudflareNets []*net.IPNet
  87. if cloudflareNets, err = initOnCloudFlareScan(); err != nil {
  88. grade = Skipped
  89. return
  90. }
  91. _, addrs, err := dnsLookupScan(addr, hostname)
  92. if err != nil {
  93. return
  94. }
  95. cfStatus := make(map[string]bool)
  96. grade = Good
  97. for _, addr := range addrs.([]string) {
  98. ip := net.ParseIP(addr)
  99. for _, cfNet := range cloudflareNets {
  100. if cfNet.Contains(ip) {
  101. cfStatus[addr] = true
  102. break
  103. }
  104. }
  105. if !cfStatus[addr] {
  106. cfStatus[addr] = false
  107. grade = Bad
  108. }
  109. }
  110. output = cfStatus
  111. return
  112. }
  113. // tcpDialScan tests that the host can be connected to through TCP.
  114. func tcpDialScan(addr, hostname string) (grade Grade, output Output, err error) {
  115. conn, err := Dialer.Dial(Network, addr)
  116. if err != nil {
  117. return
  118. }
  119. conn.Close()
  120. grade = Good
  121. return
  122. }
  123. // tlsDialScan tests that the host can perform a TLS Handshake
  124. // and warns if the server's certificate can't be verified.
  125. func tlsDialScan(addr, hostname string) (grade Grade, output Output, err error) {
  126. var conn *tls.Conn
  127. config := defaultTLSConfig(hostname)
  128. if conn, err = tls.DialWithDialer(Dialer, Network, addr, config); err != nil {
  129. return
  130. }
  131. conn.Close()
  132. config.InsecureSkipVerify = false
  133. if conn, err = tls.DialWithDialer(Dialer, Network, addr, config); err != nil {
  134. grade = Warning
  135. return
  136. }
  137. conn.Close()
  138. grade = Good
  139. return
  140. }