Class: GitHubPages::HealthCheck::Domain
- Defined in:
- lib/github-pages-health-check/domain.rb
Constant Summary collapse
- LEGACY_IP_ADDRESSES =
[ # Legacy GitHub Datacenter "207.97.227.245", "204.232.175.78", # Aug. 2016 Fastly datacenter deprecation "199.27.73.133", "199.27.76.133", # Feb. 2017 Fastly datacenter deprecation "185.31.17.133", "185.31.18.133", "185.31.19.133", "199.27.74.133", "199.27.75.133", "199.27.79.133", "23.235.39.133", "23.235.43.133", "23.235.44.133", "23.235.46.133", "23.235.47.133", "45.32.88.68" ].freeze
- CURRENT_IP_ADDRESSES =
%w( 192.30.252.153 192.30.252.154 ).freeze
- HASH_METHODS =
[ :host, :uri, :dns_resolves?, :proxied?, :cloudflare_ip?, :fastly_ip?, :old_ip_address?, :a_record?, :cname_record?, :mx_records_present?, :valid_domain?, :apex_domain?, :should_be_a_record?, :cname_to_github_user_domain?, :cname_to_pages_dot_github_dot_com?, :cname_to_fastly?, :pointed_to_github_pages_ip?, :pages_domain?, :served_by_pages?, :valid_domain?, :https?, :enforces_https?, :https_error ].freeze
Instance Attribute Summary collapse
-
#host ⇒ Object
readonly
Returns the value of attribute host.
Instance Method Summary collapse
-
#a_record? ⇒ Boolean
Is this domain’s first response an A record?.
-
#apex_domain? ⇒ Boolean
Is this domain an apex domain, meaning a CNAME would be innapropriate.
-
#check! ⇒ Object
Runs all checks, raises an error if invalid.
-
#cloudflare_ip? ⇒ Boolean
Does the domain resolve to a CloudFlare-owned IP.
-
#cname ⇒ Object
The domain to which this domain’s CNAME resolves Returns nil if the domain is not a CNAME.
-
#cname_record? ⇒ Boolean
(also: #cname?)
Is this domain’s first response a CNAME record?.
-
#cname_to_fastly? ⇒ Boolean
Is the given domain CNAME’d directly to our Fastly account?.
-
#cname_to_github_user_domain? ⇒ Boolean
Is the domain’s first response a CNAME to a pages domain?.
-
#cname_to_pages_dot_github_dot_com? ⇒ Boolean
Is the given domain a CNAME to pages.github.(io|com) instead of being CNAME’d to the user’s subdomain?.
- #deprecated_ip? ⇒ Boolean
-
#dns ⇒ Object
Returns an array of DNS answers.
-
#dns? ⇒ Boolean
(also: #dns_resolves?)
Are we even able to get the DNS record?.
-
#enforces_https? ⇒ Boolean
Does this domain redirect HTTP requests to HTTPS?.
-
#fastly? ⇒ Boolean
Is the host our Fastly CNAME?.
-
#fastly_ip? ⇒ Boolean
Does the domain resolve to a Fastly-owned IP.
-
#github_domain? ⇒ Boolean
Is this domain owned by GitHub?.
-
#https? ⇒ Boolean
Does this domain respond to HTTPS requests with a valid cert?.
-
#https_error ⇒ Object
The response code of the HTTPS request, if it failed.
-
#initialize(host) ⇒ Domain
constructor
A new instance of Domain.
- #invalid_a_record? ⇒ Boolean
- #invalid_cname? ⇒ Boolean
- #mx_records_present? ⇒ Boolean
-
#old_ip_address? ⇒ Boolean
Does this domain have any A record that points to the legacy IPs?.
-
#pages_domain? ⇒ Boolean
Is the host a *.github.io domain?.
-
#pages_dot_github_dot_com? ⇒ Boolean
Is the host pages.github.com or pages.github.io?.
-
#pointed_to_github_pages_ip? ⇒ Boolean
Is the domain’s first response an A record to a valid GitHub Pages IP?.
-
#proxied? ⇒ Boolean
Does this non-GitHub-pages domain proxy a GitHub Pages site?.
- #resolver ⇒ Object
- #served_by_pages? ⇒ Boolean
-
#should_be_a_record? ⇒ Boolean
Should the domain be an apex record?.
- #should_be_cname_record? ⇒ Boolean
- #uri(overrides = {}) ⇒ Object
-
#valid_domain? ⇒ Boolean
Is this a valid domain that PublicSuffix recognizes? Used as an escape hatch to prevent false positives on DNS checkes.
Methods inherited from Checkable
#reason, #to_hash, #to_json, #to_s, #to_s_pretty, #valid?
Constructor Details
#initialize(host) ⇒ Domain
Returns a new instance of Domain.
45 46 47 48 49 50 51 |
# File 'lib/github-pages-health-check/domain.rb', line 45 def initialize(host) unless host.is_a? String raise ArgumentError, "Expected string, got #{host.class}" end @host = normalize_host(host) end |
Instance Attribute Details
#host ⇒ Object (readonly)
Returns the value of attribute host.
5 6 7 |
# File 'lib/github-pages-health-check/domain.rb', line 5 def host @host end |
Instance Method Details
#a_record? ⇒ Boolean
Is this domain’s first response an A record?
225 226 227 228 |
# File 'lib/github-pages-health-check/domain.rb', line 225 def a_record? return unless dns? dns.first.class == Net::DNS::RR::A end |
#apex_domain? ⇒ Boolean
Is this domain an apex domain, meaning a CNAME would be innapropriate
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/github-pages-health-check/domain.rb', line 93 def apex_domain? return @apex_domain if defined?(@apex_domain) return unless valid_domain? answers = begin Resolv::DNS.open do |dns| dns.timeouts = TIMEOUT dns.getresources(absolute_domain, Resolv::DNS::Resource::IN::NS) end rescue Timeout::Error, NoMethodError [] end @apex_domain = answers.any? end |
#check! ⇒ Object
Runs all checks, raises an error if invalid
54 55 56 57 58 59 60 61 62 63 |
# File 'lib/github-pages-health-check/domain.rb', line 54 def check! raise Errors::InvalidDomainError, :domain => self unless valid_domain? raise Errors::InvalidDNSError, :domain => self unless dns_resolves? raise Errors::DeprecatedIPError, :domain => self if deprecated_ip? return true if proxied? raise Errors::InvalidARecordError, :domain => self if invalid_a_record? raise Errors::InvalidCNAMEError, :domain => self if invalid_cname? raise Errors::NotServedByPagesError, :domain => self unless served_by_pages? true end |
#cloudflare_ip? ⇒ Boolean
Does the domain resolve to a CloudFlare-owned IP
162 163 164 |
# File 'lib/github-pages-health-check/domain.rb', line 162 def cloudflare_ip? cdn_ip?(CloudFlare) end |
#cname ⇒ Object
The domain to which this domain’s CNAME resolves Returns nil if the domain is not a CNAME
240 241 242 243 |
# File 'lib/github-pages-health-check/domain.rb', line 240 def cname return unless dns.first.class == Net::DNS::RR::CNAME @cname ||= Domain.new(dns.first.cname.to_s) end |
#cname_record? ⇒ Boolean Also known as: cname?
Is this domain’s first response a CNAME record?
231 232 233 234 235 |
# File 'lib/github-pages-health-check/domain.rb', line 231 def cname_record? return unless dns? return false unless cname cname.valid_domain? end |
#cname_to_fastly? ⇒ Boolean
Is the given domain CNAME’d directly to our Fastly account?
137 138 139 |
# File 'lib/github-pages-health-check/domain.rb', line 137 def cname_to_fastly? cname? && !pages_domain? && cname.fastly? end |
#cname_to_github_user_domain? ⇒ Boolean
Is the domain’s first response a CNAME to a pages domain?
124 125 126 |
# File 'lib/github-pages-health-check/domain.rb', line 124 def cname_to_github_user_domain? cname? && !cname_to_pages_dot_github_dot_com? && cname.pages_domain? end |
#cname_to_pages_dot_github_dot_com? ⇒ Boolean
Is the given domain a CNAME to pages.github.(io|com) instead of being CNAME’d to the user’s subdomain?
domain - the domain to check, generaly the target of a cname
132 133 134 |
# File 'lib/github-pages-health-check/domain.rb', line 132 def cname_to_pages_dot_github_dot_com? cname? && cname.pages_dot_github_dot_com? end |
#deprecated_ip? ⇒ Boolean
65 66 67 68 |
# File 'lib/github-pages-health-check/domain.rb', line 65 def deprecated_ip? return @deprecated_ip if defined? @deprecated_ip @deprecated_ip = (valid_domain? && a_record? && old_ip_address?) end |
#dns ⇒ Object
Returns an array of DNS answers
190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/github-pages-health-check/domain.rb', line 190 def dns return @dns if defined? @dns return unless valid_domain? @dns = Timeout.timeout(TIMEOUT) do GitHubPages::HealthCheck.without_warnings do unless host.nil? resolver.search(absolute_domain, Net::DNS::A).answer + resolver.search(absolute_domain, Net::DNS::MX).answer end end end rescue StandardError @dns = nil end |
#dns? ⇒ Boolean Also known as: dns_resolves?
Are we even able to get the DNS record?
210 211 212 |
# File 'lib/github-pages-health-check/domain.rb', line 210 def dns? !(dns.nil? || dns.empty?) end |
#enforces_https? ⇒ Boolean
Does this domain redirect HTTP requests to HTTPS?
281 282 283 284 285 |
# File 'lib/github-pages-health-check/domain.rb', line 281 def enforces_https? return false unless https? && http_response.headers["Location"] redirect = Addressable::URI.parse(http_response.headers["Location"]) redirect.scheme == "https" && redirect.host == host end |
#fastly? ⇒ Boolean
Is the host our Fastly CNAME?
157 158 159 |
# File 'lib/github-pages-health-check/domain.rb', line 157 def fastly? !!host.match(/\Agithub\.map\.fastly\.net\.?\z/i) end |
#fastly_ip? ⇒ Boolean
Does the domain resolve to a Fastly-owned IP
167 168 169 |
# File 'lib/github-pages-health-check/domain.rb', line 167 def fastly_ip? cdn_ip?(Fastly) end |
#github_domain? ⇒ Boolean
Is this domain owned by GitHub?
152 153 154 |
# File 'lib/github-pages-health-check/domain.rb', line 152 def github_domain? !!host.downcase.end_with?("github.com") end |
#https? ⇒ Boolean
Does this domain respond to HTTPS requests with a valid cert?
270 271 272 |
# File 'lib/github-pages-health-check/domain.rb', line 270 def https? https_response.return_code == :ok end |
#https_error ⇒ Object
The response code of the HTTPS request, if it failed. Useful for diagnosing cert errors
276 277 278 |
# File 'lib/github-pages-health-check/domain.rb', line 276 def https_error https_response.return_code unless https? end |
#invalid_a_record? ⇒ Boolean
70 71 72 73 |
# File 'lib/github-pages-health-check/domain.rb', line 70 def invalid_a_record? return @invalid_a_record if defined? @invalid_a_record @invalid_a_record = (valid_domain? && a_record? && !should_be_a_record?) end |
#invalid_cname? ⇒ Boolean
75 76 77 78 79 80 81 82 83 |
# File 'lib/github-pages-health-check/domain.rb', line 75 def invalid_cname? return @invalid_cname if defined? @invalid_cname @invalid_cname = begin return false unless valid_domain? return false if github_domain? || apex_domain? return true if cname_to_pages_dot_github_dot_com? || cname_to_fastly? !cname_to_github_user_domain? && should_be_cname_record? end end |
#mx_records_present? ⇒ Boolean
245 246 247 248 |
# File 'lib/github-pages-health-check/domain.rb', line 245 def mx_records_present? return unless dns? dns.any? { |answer| answer.class == Net::DNS::RR::MX } end |
#old_ip_address? ⇒ Boolean
Does this domain have any A record that points to the legacy IPs?
216 217 218 219 220 221 222 |
# File 'lib/github-pages-health-check/domain.rb', line 216 def old_ip_address? return unless dns? dns.any? do |answer| answer.is_a?(Net::DNS::RR::A) && legacy_ip?(answer.address.to_s) end end |
#pages_domain? ⇒ Boolean
Is the host a *.github.io domain?
142 143 144 |
# File 'lib/github-pages-health-check/domain.rb', line 142 def pages_domain? !!host.match(/\A[\w-]+\.github\.(io|com)\.?\z/i) end |
#pages_dot_github_dot_com? ⇒ Boolean
Is the host pages.github.com or pages.github.io?
147 148 149 |
# File 'lib/github-pages-health-check/domain.rb', line 147 def pages_dot_github_dot_com? !!host.match(/\Apages\.github\.(io|com)\.?\z/i) end |
#pointed_to_github_pages_ip? ⇒ Boolean
Is the domain’s first response an A record to a valid GitHub Pages IP?
119 120 121 |
# File 'lib/github-pages-health-check/domain.rb', line 119 def pointed_to_github_pages_ip? a_record? && CURRENT_IP_ADDRESSES.include?(dns.first.value) end |
#proxied? ⇒ Boolean
Does this non-GitHub-pages domain proxy a GitHub Pages site?
This can be:
1. A Cloudflare-owned IP address
2. A site that returns GitHub.com server headers, but
isn't CNAME'd to a GitHub domain
3. A site that returns GitHub.com server headers, but
isn't CNAME'd to a GitHub IP
179 180 181 182 183 184 185 186 187 |
# File 'lib/github-pages-health-check/domain.rb', line 179 def proxied? return unless dns? return true if cloudflare_ip? return false if pointed_to_github_pages_ip? return false if cname_to_github_user_domain? return false if cname_to_pages_dot_github_dot_com? return false if cname_to_fastly? || fastly_ip? served_by_pages? end |
#resolver ⇒ Object
205 206 207 |
# File 'lib/github-pages-health-check/domain.rb', line 205 def resolver @resolver ||= Net::DNS::Resolver.new end |
#served_by_pages? ⇒ Boolean
250 251 252 253 254 255 256 257 258 259 260 261 |
# File 'lib/github-pages-health-check/domain.rb', line 250 def served_by_pages? return @served_by_pages if defined? @served_by_pages return unless dns_resolves? @served_by_pages = begin return false unless response.mock? || response.return_code == :ok return true if response.headers["Server"] == "GitHub.com" # Typhoeus mangles the case of the header, compare insensitively response.headers.any? { |k, _v| k =~ /X-GitHub-Request-Id/i } end end |
#should_be_a_record? ⇒ Boolean
Should the domain be an apex record?
110 111 112 |
# File 'lib/github-pages-health-check/domain.rb', line 110 def should_be_a_record? !pages_domain? && (apex_domain? || mx_records_present?) end |
#should_be_cname_record? ⇒ Boolean
114 115 116 |
# File 'lib/github-pages-health-check/domain.rb', line 114 def should_be_cname_record? !should_be_a_record? end |
#uri(overrides = {}) ⇒ Object
263 264 265 266 267 |
# File 'lib/github-pages-health-check/domain.rb', line 263 def uri(overrides = {}) = { :host => host, :scheme => scheme, :path => "/" } = .merge(overrides) Addressable::URI.new().normalize.to_s end |
#valid_domain? ⇒ Boolean
Is this a valid domain that PublicSuffix recognizes? Used as an escape hatch to prevent false positives on DNS checkes
87 88 89 90 |
# File 'lib/github-pages-health-check/domain.rb', line 87 def valid_domain? return @valid if defined? @valid @valid = PublicSuffix.valid?(host, :default_rule => nil) end |