chkdfront 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 56a52ddfb0d5fbbfd69cb1e231bd8e5545d9a7c0467a5a438d1c7783029db7ed
4
+ data.tar.gz: 4187aec0c81896522bcef3a528cdf9057fd5e747209a5ff80fedc367a94093b6
5
+ SHA512:
6
+ metadata.gz: f3f6407453d3ddf42344038bcfa085031d6d6a4192989b6d08c7d19d86238ac73fad971fd7576c5ddbec238a19c3c35a0d3ac1376e3020bae76bea72b3b26eb6
7
+ data.tar.gz: c2e3c72f7efd6079542404911238cd46a6127865c7e3e3a261de699c5800b924b0fed1f74b1a2fd7ae8362019678989e9cc4ebab61fd32c6dc1b27118aa4dc23
data/.gitignore ADDED
@@ -0,0 +1,146 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ ### macOS template
10
+ # General
11
+ .DS_Store
12
+ .AppleDouble
13
+ .LSOverride
14
+
15
+ # Icon must end with two \r
16
+ Icon
17
+
18
+ # Thumbnails
19
+ ._*
20
+
21
+ # Files that might appear in the root of a volume
22
+ .DocumentRevisions-V100
23
+ .fseventsd
24
+ .Spotlight-V100
25
+ .TemporaryItems
26
+ .Trashes
27
+ .VolumeIcon.icns
28
+ .com.apple.timemachine.donotpresent
29
+
30
+ # Directories potentially created on remote AFP share
31
+ .AppleDB
32
+ .AppleDesktop
33
+ Network Trash Folder
34
+ Temporary Items
35
+ .apdisk
36
+ ### Ruby template
37
+ *.gem
38
+ *.rbc
39
+ /.config
40
+ /coverage/
41
+ /InstalledFiles
42
+ /pkg/
43
+ /spec/reports/
44
+ /spec/examples.txt
45
+ /test/tmp/
46
+ /test/version_tmp/
47
+ /tmp/
48
+
49
+ # Used by dotenv library to load environment variables.
50
+ # .env
51
+
52
+ ## Specific to RubyMotion:
53
+ .dat*
54
+ .repl_history
55
+ build/
56
+ *.bridgesupport
57
+ build-iPhoneOS/
58
+ build-iPhoneSimulator/
59
+
60
+ ## Specific to RubyMotion (use of CocoaPods):
61
+ #
62
+ # We recommend against adding the Pods directory to your .gitignore. However
63
+ # you should judge for yourself, the pros and cons are mentioned at:
64
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
65
+ #
66
+ # vendor/Pods/
67
+
68
+ ## Documentation cache and generated files:
69
+ /.yardoc/
70
+ /_yardoc/
71
+ /doc/
72
+ /rdoc/
73
+
74
+ ## Environment normalization:
75
+ /.bundle/
76
+ /vendor/bundle
77
+ /lib/bundler/man/
78
+
79
+ # for a library or gem, you might want to ignore these files since the code is
80
+ # intended to run in multiple environments; otherwise, check them in:
81
+ # Gemfile.lock
82
+ # .ruby-version
83
+ # .ruby-gemset
84
+
85
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
86
+ .rvmrc
87
+ ### JetBrains template
88
+ # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
89
+ # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
90
+
91
+ # User-specific stuff
92
+ .idea/**/workspace.xml
93
+ .idea/**/tasks.xml
94
+ .idea/**/dictionaries
95
+ .idea/**/shelf
96
+
97
+ # Sensitive or high-churn files
98
+ .idea/**/dataSources/
99
+ .idea/**/dataSources.ids
100
+ .idea/**/dataSources.local.xml
101
+ .idea/**/sqlDataSources.xml
102
+ .idea/**/dynamic.xml
103
+ .idea/**/uiDesigner.xml
104
+ .idea/**/dbnavigator.xml
105
+
106
+ # Gradle
107
+ .idea/**/gradle.xml
108
+ .idea/**/libraries
109
+
110
+ # CMake
111
+ cmake-build-debug/
112
+ cmake-build-release/
113
+
114
+ # Mongo Explorer plugin
115
+ .idea/**/mongoSettings.xml
116
+
117
+ # File-based project format
118
+ *.iws
119
+
120
+ # IntelliJ
121
+ out/
122
+
123
+ # mpeltonen/sbt-idea plugin
124
+ .idea_modules/
125
+
126
+ # JIRA plugin
127
+ atlassian-ide-plugin.xml
128
+
129
+ # Cursive Clojure plugin
130
+ .idea/replstate.xml
131
+
132
+ # Crashlytics plugin (for Android Studio and IntelliJ)
133
+ com_crashlytics_export_strings.xml
134
+ crashlytics.properties
135
+ crashlytics-build.properties
136
+ fabric.properties
137
+
138
+ # Editor-based Rest Client
139
+ .idea/httpRequests
140
+ ### VisualStudioCode template
141
+ .vscode/*
142
+ !.vscode/settings.json
143
+ !.vscode/tasks.json
144
+ !.vscode/launch.json
145
+ !.vscode/extensions.json
146
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in chkdfront.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # Chkdfront
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/chkdfront`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'chkdfront'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install chkdfront
22
+
23
+ ## Usage
24
+
25
+ ```
26
+ MMMMMMMMMMMMMWNK0kdolc;,'... .;KMMMMMMMMMMMMMMMMMMMMMMMMMMM
27
+ MMMMMMMMMN0xl;'. lNMMMMMMMMMMMMMMMMMMMMMMMMMM
28
+ MMMMMWKxc'. .kWMMMMMMMMMMMMMMMMMMMMMMMMM
29
+ MMN0o;. ;XMMMMMMMMMMMMMMMMMMMMMMMMM
30
+ Ol,. .xWMMMMMMMMMMMMMMMMMMMMMMMM
31
+ ' . ;XMMMMMMMMMMMMMMMMMMMMMMMM
32
+ l .;dO00ko;'. .kMMMMMMMMMMMMMMMMMMMMMMMM
33
+ X: .dKNWWXOl,. oWMMMMMMMMMMMMMMMMMMMMMMM
34
+ M0, 'ldkx; .',,..,;:cc;dNMMMMMMMMMMMMMMMMMMMMMMM
35
+ MWk. .dNMMWk. ;ONWWWWWWMMMMMMMMMMMMMMMMMMMMMMMM
36
+ MMWx. lXXKkc. :XMXOo;;coxOKNWMMMMMMMMMMMMMMMMMMM
37
+ MMMWx. .... ;KMXc. .';cdkKNMMMMMMMMMMMMMM
38
+ MMMMWk. .:oxxkXMNl .,cx0NMMMMMMMMMM
39
+ MMMMMWO, .oXWWXNMMNo. .,lONMMMMMMM
40
+ MMMMMMMXl. .kNOo,;OWWx. 'lONMMMM
41
+ MMMMMMMMWO; .lx;. lNMO' .,dKWM
42
+ MMMMMMMMMMNx;. .. ,0MX: .,:ll:,. .:x
43
+ MMMMMMMMMMMMNOc. .dWWx. .'lXWMNOc. .
44
+ MMMMMMMMMMMMMMWXOo:':KMX: .cxO0k; .o
45
+ MMMMMMMMMMMMMMMMMMWNNWMk. ,odol,. .dN
46
+ MMMMMMMMMMMMMMMMMMMMMMWo .dXWMWO: .dNM
47
+ MMMMMMMMMMMMMMMMMMMMMMNc ;, 'cdxko. .kWMM
48
+ MMMMMMMMMMMMMMMMMMMMMMNc lKOl. ;0WMMM
49
+ MMMMMMMMMMMMMMMMMMMMMMWo ,KMW0l. .lXMMMMM
50
+ MMMMMMMMMMMMMMMMMMMMMMMk. :kKMWXOdolcc:,. ,kWMMMMMM
51
+ MMMMMMMMMMMMMMMMMMMMMMMNc .'o0XNNNKOo;. 'dXMMMMMMMM
52
+ MMMMMMMMMMMMMMMMMMMMMMMMK; ..''.. 'dXWMMMMMMMMM
53
+ MMMMMMMMMMMMMMMMMMMMMMMMMKc .:xXMMMMMMMMMMMM
54
+ MMMMMMMMMMMMMMMMMMMMMMMMMMNk;. .'cxKWMMMMMMMMMMMMMM
55
+ MMMMMMMMMMMMMMMMMMMMMMMMMMMMNxl:'....':oOXWMMMMMMMMMMMMMMMMM
56
+
57
+ ```
58
+
59
+ ## Development
60
+
61
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
62
+
63
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
64
+
65
+ ## Contributing
66
+
67
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/chkdfront.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
data/bin/chkdfront ADDED
@@ -0,0 +1,173 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # @Author: KING SABRI - @KINGSABRI
4
+ #
5
+ require 'chkdfront'
6
+
7
+ logo = %Q{
8
+ MMMMMMMMMMMMMWNK0kdolc;,' ;KMMMMMMMMMMMMMMMMMMMMMMMMMMM
9
+ MMMMMMMMMN0xl;'. lNMMMMMMMMMMMMMMMMMMMMMMMMMM
10
+ MMMMMWKxc'. .kWMMMMMMMMMMMMMMMMMMMMMMMMM
11
+ MMN0o;. ;XMMMMMMMMMMMMMMMMMMMMMMMMM
12
+ Ol,. .xWMMMMMMMMMMMMMMMMMMMMMMMM
13
+ ' . ;XMMMMMMMMMMMMMMMMMMMMMMMM
14
+ l .;dO00ko;'. .kMMMMMMMMMMMMMMMMMMMMMMMM
15
+ X: .dKNWWXOl,. oWMMMMMMMMMMMMMMMMMMMMMMM
16
+ M0, 'ldkx; .',,..,;:cc;dNMMMMMMMMMMMMMMMMMMMMMMM
17
+ MWk. .doMaiN. ;ONWWWWWWMMMMMMMMMMMMMMMMMMMMMMMM
18
+ MMWx. lXXKkc. :XMXOo;;coxOKNWMMMMMMMMMMMMMMMMMMM
19
+ MMMWx. .... ;KMXc. .';cdkKNMMMMMMMMMMMMMM
20
+ MMMMWk. .:oxxkXMNl .,cx0NMMMMMMMMMM
21
+ MMMMMWO, .oXWWXNMMNo. .,lONMMMMMMM
22
+ MMMMMMMXl. .kNOo,;OWWx. 'lONMMMM
23
+ MMMMMMMMWO; .lx;. lNMO' .,dKWM
24
+ MMMMMMMMMMNx;. .. ,0MX: .,:ll:,. .:x
25
+ MMMMMMMMMMMMNOc. .dWWx. .'lXWMNOc. .
26
+ MMMMMMMMMMMMMMWXOo:':KMX: .cxO0k; .o
27
+ MMMMMMMMMMMMMMMMMMWNNWMk. ,domain. .N
28
+ MMMMMMMMMMMMMMMMMMMMMMWo .fronting .dNM
29
+ MMMMMMMMMMMMMMMMMMMMMMNc ;, 'cdxko. .kWMM
30
+ MMMMMMMMMMMMMMMMMMMMMMNc lKOl. ;0WMMM
31
+ MMMMMMMMMMMMMMMMMMMMMMWo ,KMW0l. .lXMMMMM
32
+ MMMMMMMMMMMMMMMMMMMMMMMk. :kKMWXOdolcc:,. ,kWMMMMMM
33
+ MMMMMMMMMMMMMMMMMMMMMMMNc .'o0XNNNKOo;. 'dXMMMMMMMM
34
+ MMMMMMMMMMMMMMMMMMMMMMMMK; ..''.. 'dXWMMMMMMMMM
35
+ MM By: #{'@KINGSABRI'.bold} MMMMMMKc .:xXMMMMMMMMMMMM
36
+ MM #{'chkdfront'.bold} v#{ChkDFront::VERSION} MMMMNk;. .'cxKWMMMMMMMMMMMMMM
37
+ MMMMMMMMMMMMMMMMMMMMMMMMMMMMNxl:'....':oOXWMMMMMMMMMMMMMMMMM
38
+ }
39
+
40
+ CLI::UI::StdoutRouter.enable
41
+
42
+ options = OpenStruct.new(
43
+ front_target: nil, domain_front: nil, provider: :auto,
44
+ expect: nil, proxy: nil, debug: false, tshoot: false
45
+ )
46
+ option_parser = OptionParser.new do |opts|
47
+ opts.banner = "Check DomainFront (chkdfront) - A tool verifies domain fronting."
48
+ opts.separator ""
49
+ opts.separator "Help menu:"
50
+
51
+ opts.on("-f", "--front-target URL", "Fronted target domain or URL.", "\te.g. images.businessweek.com") do |o|
52
+ options.front_target = o
53
+ end
54
+
55
+ opts.on("-d", "--domain-front DOMAIN", "DomainFront domain.", "\te.g. df36z1umwj2fze.cloudfront.net") do |o|
56
+ options.domain_front = o
57
+ end
58
+
59
+ opts.on("-e", "--expect STRING", "Expect a given string that indicates success. (case-sensitive)", "\te.g. It works") do |o|
60
+ options.expect = o
61
+ end
62
+
63
+ opts.on("-p", "--provider NUM",
64
+ "Choose CDN / Domain Front Provider:", Integer,
65
+ "\t[0] Auto (default - auto tune request. Extra request to detect)",
66
+ "\t[1] Amazon (tune request for Amazon domain fronting)",
67
+ "\t[2] Azure (tune request for Azure domain fronting)",
68
+ "\t[3] Alibaba (tune request for Alibaba domain fronting)") do |provider|
69
+ case provider.to_i
70
+ when 0
71
+ options.provider = :auto
72
+ when 1
73
+ options.provider = :amazon
74
+ when 2
75
+ options.provider = :azure
76
+ when 3
77
+ options.provider = :alibaba
78
+ else
79
+ puts "[!] Unknown Provider: switching to auto.."
80
+ options.provider = :auto
81
+ end
82
+ end
83
+
84
+ opts.on("-t", "--troubleshoot [DOMAIN]", "Force troubleshooting procedures.",
85
+ "execute troubleshooting procedures(ping, http, nslookup) for all parties",
86
+ "(optional: original domain where CDN forwards, to include in the checks)",
87
+ "\te.g. c2.mydomain.com") do |o|
88
+ options.tshoot = o
89
+ end
90
+
91
+ opts.on("--proxy USER:PASS@HOST:PORT", "Use proxy settings if you're behind proxy.",
92
+ "\te.g. user1:Pass123@localhost:8080") do |o|
93
+ options.proxy = o
94
+ end
95
+
96
+ opts.on("--debug", "Force debugging.",
97
+ "show response's body and low-level request and response debug trace.",
98
+ "(default enabled when test fails.)"
99
+ ) do |o|
100
+ options.debug = o
101
+ end
102
+
103
+ opts.on("-h", "--help", "Show this message.") do
104
+ puts logo
105
+ puts opts
106
+ exit!
107
+ end
108
+
109
+ opts.on_tail "\nUsage:\n" + " #{$PROGRAM_NAME} <OPTIONS>"
110
+ opts.on_tail "Example:"
111
+ opts.on_tail %{ #{$PROGRAM_NAME} -f images.businessweek.com -d df36z1umwj2fze.cloudfront.net}
112
+ opts.on_tail %{ #{$PROGRAM_NAME} -f images.businessweek.com -d df36z1umwj2fze.cloudfront.net --debug -t c2.mysite.com\n\n}
113
+ end
114
+
115
+ begin
116
+ option_parser.parse!(ARGV)
117
+ if (options.front_target || options.domain_front).nil?
118
+ puts option_parser
119
+ end
120
+
121
+ # list of hosts to troubleshoot later
122
+ hosts = [options.front_target, options.domain_front, options.tshoot].compact
123
+ cli = ChkDFront::CliOperations.new
124
+
125
+ if options.front_target && options.domain_front
126
+ spnr_opts = {output: $stdout, clear: true, format: :arrow_pulse, hide_cursor: true}
127
+ spinner = TTY::Spinner.new("[:spinner] please wait!", spnr_opts)
128
+ spinner.auto_spin
129
+
130
+ http = ChkDFront::Request.new(options.front_target, options.domain_front, options.proxy)
131
+ http.send_to(cli.find_provider(options.provider, options.domain_front))
132
+ cli.http = http
133
+ cli.request = http.request
134
+ cli.response = http.response
135
+
136
+ res = http.response
137
+ # if the request succeeded
138
+ if res.code.to_i == 200
139
+ CLI::UI::Frame.open('Request', color: :bold, timing: false) do
140
+ CLI::UI::Frame.open("Response | #{res.message} (#{res.code})", color: :green, timing: false) do
141
+ cli.show_success
142
+ cli.show_expected(options.expect) if options.expect
143
+ cli.show_body; cli.show_debug if options.debug
144
+ end
145
+ end
146
+ # if the user want to troubleshoot even request has succeeded
147
+ if options.tshoot || options.tshoot.nil?
148
+ CLI::UI::Frame.open('Troubleshooting'.bold, color: :magenta, timing: false) do
149
+ cli.troubleshoot(hosts)
150
+ end
151
+ end
152
+ else # If request failed, troubleshoot
153
+ CLI::UI::Frame.open('Request', color: :bold, timing: false) do
154
+ CLI::UI::Frame.open("Response | #{res.message} (#{res.code})", color: :red, timing: false) do
155
+ cli.show_checks
156
+ cli.show_body
157
+ cli.show_debug
158
+ end
159
+ end
160
+ CLI::UI::Frame.open('Troubleshooting', color: :magenta, timing: false) { cli.troubleshoot(hosts) }
161
+ end
162
+ end
163
+ rescue OptionParser::MissingArgument => e
164
+ puts option_parser
165
+ e.args.each {|arg| puts '[!] '+ "#{e.reason.capitalize} for '#{arg}' option."}
166
+ rescue OptionParser::InvalidOption => e
167
+ puts option_parser
168
+ pp e
169
+ rescue Exception => e
170
+ puts "#{$PROGRAM_NAME} Exception".error
171
+ puts e.backtrace_locations
172
+ puts e
173
+ end
data/chkdfront.gemspec ADDED
@@ -0,0 +1,38 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "chkdfront/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'chkdfront'
8
+ spec.version = ChkDFront::VERSION
9
+ spec.authors = ['@KINGSABRI']
10
+ spec.email = ['king.sabri@gmail.com']
11
+
12
+ spec.summary = %q{Check Domain Fronting (chkdfront) - It checks if domain fronting is working.}
13
+ spec.description = %q{Check Domain Fronting (chkdfront) - It checks if domain fronting implementation is working.}
14
+ spec.homepage = 'https://github.com/KINGSABRI/chkdfront'
15
+ spec.licenses = ['MIT']
16
+
17
+ # Specify which files should be added to the gem when it is released.
18
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
20
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
+ end
22
+
23
+ spec.executables = ['chkdfront']
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_dependency 'cli-ui'
27
+ spec.add_dependency 'tty-spinner'
28
+ spec.add_dependency 'word_wrap'
29
+ spec.add_dependency 'net-ping'
30
+ spec.add_dependency 'net-dns'
31
+ spec.add_dependency 'adomain'
32
+
33
+ spec.add_development_dependency "bundler", "~> 2.0"
34
+ spec.add_development_dependency "rake", "~> 10.0"
35
+
36
+ spec.metadata['source_code_uri'] = 'https://github.com/KINGSABRI/chkdfront'
37
+ spec.metadata['bug_tracker_uri'] = 'https://github.com/KINGSABRI/chkdfront/issues'
38
+ end
@@ -0,0 +1,126 @@
1
+ class String
2
+ def red; colorize(self, "\e[1m\e[31m"); end
3
+ def green; colorize(self, "\e[1m\e[32m"); end
4
+ def dark_green; colorize(self, "\e[32m"); end
5
+ def yellow; colorize(self, "\e[1m\e[33m"); end
6
+ def blue; colorize(self, "\e[1m\e[34m"); end
7
+ def dark_blue; colorize(self, "\e[34m"); end
8
+ def purple; colorize(self, "\e[35m"); end
9
+ def dark_purple; colorize(self, "\e[1;35m"); end
10
+ def cyan; colorize(self, "\e[1;36m"); end
11
+ def dark_cyan; colorize(self, "\e[36m"); end
12
+ def pure; colorize(self, "\e[0m\e[28m"); end
13
+ def bold; colorize(self, "\e[1m"); end
14
+ def error; colorize(self, "\n[" + " ✖ ".red + "] "); end
15
+ def colorize(text, color_code) "#{color_code}#{text}\e[0m" end
16
+ end
17
+
18
+ module ChkDFront
19
+ class CliOperations
20
+ include ChkDFront::Providers
21
+ attr_accessor :http, :request, :response
22
+ def initialize
23
+ @http = nil
24
+ @request = nil
25
+ @response = nil
26
+
27
+ @regx_domain = /^(?:https?:\/\/)?(?:[^@\n]+@)?([^:\/\n?]+)/ # extract domain from url
28
+ @options = { output: $stdout, format: :pulse_2, success_mark: " ✔ ".green, error_mark: " ✖ ".red, hide_cursor: true }
29
+ end
30
+
31
+ def show_success
32
+ puts CLI::UI.fmt "{{v}} Front target: " + "#{@http.front_target.host}"
33
+ puts CLI::UI.fmt "{{v}} Provider header: " + "#{@response['Via']}"
34
+ puts CLI::UI.fmt "{{v}} Domain front: " + "#{@http.domain_front}"
35
+ end
36
+
37
+ def show_expected(string)
38
+ CLI::UI::Frame.divider('Expected String')
39
+ if @response.body.include?(string)
40
+ puts CLI::UI.fmt "{{v}} Found: " + "#{string}"
41
+ else
42
+ puts CLI::UI.fmt "{{x}} Not Found: " + "#{string}"
43
+ end
44
+ end
45
+
46
+ def show_checks
47
+ puts @http.res_err[:checks]
48
+ end
49
+
50
+ def show_body
51
+ CLI::UI::Frame.divider('Response Body')
52
+ puts @response.body
53
+ end
54
+ def show_debug
55
+ CLI::UI::Frame.divider('Debugging')
56
+ puts WordWrap.ww(@http.debug_output, CLI::UI::Terminal.width)
57
+ end
58
+
59
+ # Find provider if not given by the user
60
+ # @param [Symbol] provider_name
61
+ # given by 'options.provider' option.
62
+ # Default is :auto, accepted is :amazon, :azure, :alibaba
63
+ # @param [String] domain_front
64
+ # given by 'options.domain_front' option.
65
+ def find_provider(provider_name, domain_front)
66
+ @options[:format] = :dots_9
67
+ spinner = TTY::Spinner.new("[:spinner] Auto-detecting", @options)
68
+ case provider_name
69
+ when :auto
70
+ domain = Adomain.domain(domain_front)
71
+ [amazon, azure, alibaba].map do |provider|
72
+ if provider[:dfront].include?(domain)
73
+ # spinner.update(title: "Provider found: #{provider[:name].bold}")
74
+ # spinner.reset
75
+ spinner.success(" | Provider found: #{provider[:name].bold}")
76
+ return provider[:name].downcase.to_sym
77
+ end
78
+ end
79
+ when :amazon || :azure || :alibaba
80
+ provider_name
81
+ else
82
+ spinner.error("Failed to auto detect provider: please use '-p' and choose from: 1, 2 or 3")
83
+ end
84
+ end
85
+
86
+ def troubleshoot(hosts = [])
87
+ icmp_ping hosts
88
+ http_ping hosts
89
+ dns_ping hosts
90
+ end
91
+
92
+ def icmp_ping(hosts)
93
+ CLI::UI::Frame.divider('ICMP Ping', color: :reset)
94
+ hosts.map do |host|
95
+ host = host.scan(@regx_domain).join
96
+ spinner = TTY::Spinner.new("[:spinner] pinging #{host}", @options)
97
+ icmp = ChkDFront::Troubleshoot.icmp_ping(host)
98
+ icmp.ping? ? spinner.success : spinner.error
99
+ end
100
+ end
101
+
102
+ def http_ping(hosts)
103
+ CLI::UI::Frame.divider('HTTP Ping', color: :reset)
104
+ hosts.map do |host|
105
+ host = host.scan(@regx_domain).join
106
+ spinner = TTY::Spinner.new("[:spinner] pinging #{host}", @options)
107
+ http = ChkDFront::Troubleshoot.http_ping(host)
108
+ http.ping? ? spinner.success : spinner.error
109
+ puts http.exception unless http.ping?
110
+ end
111
+ end
112
+
113
+ def dns_ping(hosts)
114
+ CLI::UI::Frame.divider('NSlookup (CNAME)', color: :reset)
115
+ hosts.map do |host|
116
+ host = host.scan(@regx_domain).join
117
+ spinner = TTY::Spinner.new("[:spinner] nslookup #{host}", @options)
118
+ dns = ChkDFront::Troubleshoot.dns_ping(host)
119
+ dns.empty? ? spinner.error : spinner.success
120
+ puts dns
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+
@@ -0,0 +1,68 @@
1
+ module ChkDFront
2
+ # This module contains CDN provider specific settings headers.
3
+ module Providers
4
+ def get_provider(provider, domain_front)
5
+ if domain_front.port
6
+ host = "#{domain_front.host}:#{domain_front.port}"
7
+ else
8
+ host = domain_front.host
9
+ end
10
+ case provider
11
+ when :amazon then amazon(host)
12
+ when :azure then azure(host)
13
+ when :alibaba then alibaba(host)
14
+ else
15
+ puts "Unknown Provider!!!!: #{provider}"
16
+ return false
17
+ end
18
+ end
19
+
20
+ # Amazon vendor specific settings and headers
21
+ # @param [String] host
22
+ # @return [Hash]
23
+ # Returns a hash of { dfront: [domain1, domain2], headers: {}}
24
+ def amazon(host='')
25
+ {
26
+ name: 'Amazon',
27
+ dfront: ['cloudfront.net'],
28
+ headers: {
29
+ 'Host' => host,
30
+ 'User-Agent' => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:65.0) Gecko/20100101 Firefox/65.0",
31
+ 'Connection' => 'close'
32
+ }
33
+ }
34
+ end
35
+
36
+ # Azure vendor specific settings and headers
37
+ # @param [String] host
38
+ # @return [Hash]
39
+ # Returns a hash of { dfront: [domain1, domain2], headers: {}}
40
+ def azure(host='')
41
+ {
42
+ name: 'Azure',
43
+ dfront: ['azureedge.net'],
44
+ headers: {
45
+ 'Host' => host,
46
+ 'User-Agent' => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:65.0) Gecko/20100101 Firefox/65.0",
47
+ 'Connection' => 'close'
48
+ }
49
+ }
50
+ end
51
+
52
+ # Alibaba vendor specific settings and headers
53
+ # @param [String] host
54
+ # @return [Hash]
55
+ # Returns a hash of { dfront: [domain1, domain2], headers: {}}
56
+ def alibaba(host='')
57
+ {
58
+ name: 'Alibaba',
59
+ dfront: ['kunlungr.com'],
60
+ headers: {
61
+ 'Host' => host,
62
+ 'User-Agent' => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:65.0) Gecko/20100101 Firefox/65.0",
63
+ 'Connection' => 'close'
64
+ }
65
+ }
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,179 @@
1
+ module ChkDFront
2
+ # Contains all HTTP request related functionalities
3
+ class Request
4
+ include ChkDFront::Providers
5
+
6
+ # @attribute [r] front_target
7
+ # @return [String] front_target
8
+ attr_reader :front_target
9
+ # @!attribute [r] domain_front
10
+ # @return [String]
11
+ attr_reader :domain_front
12
+ # @!attribute [r] proxy
13
+ # @return [String]
14
+ attr_reader :proxy
15
+ # @!attribute [r]
16
+ # @return [String]
17
+ attr_reader :debug_output
18
+ # @!attribute [r] request
19
+ # @return [Net::HTTP::Request]
20
+ attr_reader :request
21
+ # @!attribute [r] request
22
+ # @return [Net::HTTP::Response]
23
+ attr_reader :response
24
+ # @!attribute [r] res_err
25
+ # @return [Hash]
26
+ attr_reader :res_err
27
+
28
+ def initialize(front_target, domain_front, proxy)
29
+ @front_target = format_front_target(front_target)
30
+ @domain_front = format_domain_front(domain_front)
31
+ @proxy = format_proxy(proxy)
32
+ @http = setup_http
33
+ end
34
+
35
+ # Send GET/POST request to the targeted domain
36
+ #
37
+ # @param [Symbol] provider_name
38
+ # Available providers symbols:
39
+ # - :amazon
40
+ # - :azure
41
+ # - :alibaba
42
+ # @param [String] http_method
43
+ # @return [Object]
44
+ def send_to(provider_name, http_method='get')
45
+ provider = get_provider(provider_name, @domain_front)
46
+ @request = Net::HTTP.const_get(http_method.capitalize).new(
47
+ @front_target.request_uri, provider[:headers]
48
+ )
49
+ @response = @http.request(@request)
50
+ check_http(@response) # if response failed, give the user some suggestion
51
+ rescue SocketError => e
52
+ puts "#{self.class}##{__method__}:".error
53
+ puts e.message
54
+ rescue Net::ReadTimeout => e
55
+ puts "#{self.class}##{__method__}:".error
56
+ puts e.message
57
+ puts "Remote port is closed.".error
58
+ exit!
59
+ rescue Exception => e
60
+ puts "#{self.class}##{__method__}:".error
61
+ puts e.full_message
62
+ end
63
+
64
+ private
65
+
66
+ # @param [String] front_target
67
+ # The domain of fronted domain (e.g. images.businessweek.com)
68
+ # This domain should be on the same CDN that user already uses
69
+ # @return [OpenStruct]
70
+ def format_front_target(front_target)
71
+ front_target = "http://#{front_target}" unless front_target.match(/^(http|https):\/\//i)
72
+ uri = URI.parse(front_target)
73
+ OpenStruct.new(host: uri.host, port: uri.port, scheme: uri.scheme, request_uri: uri.request_uri)
74
+ end
75
+
76
+ # @param [String] domain_front
77
+ # The CDN's domain front (e.g. df36z1umwj2fze.cloudfront.net)
78
+ # this domain is what the users create by their provider.
79
+ # @return [String]
80
+ def format_domain_front(domain_front)
81
+ # if the user gave a URL instead a FQDN:PORT, parse it
82
+ # Otherwise just use what you get
83
+ uri = URI.parse(domain_front)
84
+ if uri.scheme
85
+ OpenStruct.new(host: uri.host, port: uri.port)
86
+ else
87
+ host, port = domain_front.split(':')
88
+ OpenStruct.new(host: host, port: port)
89
+ end
90
+ end
91
+
92
+ #
93
+ # @param [String] proxy
94
+ # The accepted proxy format is:
95
+ # - Username and Password separated by column
96
+ # - Hostname and Port separated by column
97
+ # - Both above parts separated by @ sign
98
+ # @example
99
+ # user1:Pass123@localhost:8080
100
+ #
101
+ # @return [OpenStruct]
102
+ def format_proxy(proxy)
103
+ if proxy
104
+ p_url, p_creds = proxy.reverse&.split('@', 2).map(&:reverse)
105
+ p_host, p_port = p_url.split(':') if p_url
106
+ p_user, p_pass = p_creds.split(':', 2) if p_creds
107
+ end
108
+ OpenStruct.new(host: p_host, port: p_port, user: p_user, pass: p_pass)
109
+ end
110
+
111
+ # @private
112
+ # Setups the initial http connection settings.
113
+ # The @!method #send_to is going to use it later
114
+ # @return [Net::HTTP]
115
+ def setup_http
116
+ http = Net::HTTP.new(@front_target.host, @front_target.port,
117
+ @proxy.host, @proxy.port,
118
+ @proxy.user, @proxy.pass)
119
+ http.use_ssl = true if @front_target.scheme =~ /https/i
120
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
121
+ http.open_timeout = 5
122
+ http.read_timeout = 5
123
+ @debug_output = ""
124
+ http.set_debug_output(@debug_output)
125
+ return http
126
+ rescue Exception => e
127
+ puts "#{self.class}##{__method__}:".error
128
+ puts e.full_message
129
+ end
130
+
131
+ # @param [] response
132
+ # HTTP response error-based suggestions.
133
+ # If request fail, it checks the response type and suggest checks based on the error.
134
+ # These suggestion are based on our experience to help users to troubleshoot.
135
+ # If you've faced different cases and responses, please report it us to update the list
136
+ # @todo: move this to a yaml or json file instead
137
+ def check_http(response)
138
+ case response
139
+ when Net::HTTPOK
140
+ response
141
+ when Net::HTTPGatewayTimeOut
142
+ @res_err = {
143
+ orig: response,
144
+ checks: [
145
+ "Check your original server:",
146
+ " is server up?",
147
+ " is service up?",
148
+ " is service port correct?",
149
+ ]
150
+ }
151
+ when Net::HTTPBadGateway
152
+ @res_err = {
153
+ orig: response,
154
+ checks: [
155
+ "- Check your original server:",
156
+ " - is server up?",
157
+ " - is service up?",
158
+ " - is service port correct?",
159
+ "- Check your provider:",
160
+ " - is front domain name correct? (#{@domain_front})",
161
+ " - is destination port correct?.",
162
+ ]
163
+ }
164
+ when Net::HTTPForbidden
165
+ @res_err = {
166
+ orig: response,
167
+ checks: [
168
+ "- Check your provider:",
169
+ " - is front domain name correct? (#{@domain_front})",
170
+ "- Check your target:",
171
+ " - is target domain correct? (#{@front_target.host})",
172
+ " - is target port correct? (#{@front_target.port})"
173
+ ]
174
+ }
175
+ end
176
+ end
177
+ end
178
+ end
179
+
@@ -0,0 +1,22 @@
1
+ module ChkDFront
2
+ # Contains all troubleshooting functionalities.
3
+ # Currently, ping, http, nslookup
4
+ class Troubleshoot
5
+ def self.icmp_ping(host)
6
+ Net::Ping::External.new(host)
7
+ end
8
+
9
+ def self.http_ping(host)
10
+ host = "http://#{host}" unless host.match(/^(http|https):\/\//i)
11
+ Net::Ping::HTTP.new(host)
12
+ end
13
+
14
+ def self.dns_ping(host)
15
+ dns = Net::DNS::Resolver.start(host)
16
+ dns.answer.select {|r| r.type == "CNAME"}&.map(&:cname)
17
+ rescue Exception => e
18
+ puts e.message
19
+ return []
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module ChkDFront
2
+ VERSION = "1.0.1"
3
+ end
data/lib/chkdfront.rb ADDED
@@ -0,0 +1,24 @@
1
+ # Standard libraries
2
+ require 'optparse'
3
+ require 'ostruct'
4
+ require 'net/http'
5
+ require 'openssl'
6
+
7
+ # Chkdfront
8
+ require 'chkdfront/version'
9
+ require 'chkdfront/providers'
10
+ require 'chkdfront/request'
11
+ require 'chkdfront/troubleshoot'
12
+ require 'chkdfront/cli_operations'
13
+
14
+ # External libraries
15
+ require 'cli/ui'
16
+ require 'tty-spinner'
17
+ require 'word_wrap'
18
+ require 'net/ping'
19
+ require 'net/dns'
20
+ require 'adomain'
21
+
22
+ module ChkDFront
23
+ class Error < StandardError; end
24
+ end
metadata ADDED
@@ -0,0 +1,171 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chkdfront
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - "@KINGSABRI"
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-04-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: cli-ui
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: tty-spinner
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: word_wrap
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: net-ping
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: net-dns
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: adomain
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: bundler
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '2.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '2.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '10.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '10.0'
125
+ description: Check Domain Fronting (chkdfront) - It checks if domain fronting implementation
126
+ is working.
127
+ email:
128
+ - king.sabri@gmail.com
129
+ executables:
130
+ - chkdfront
131
+ extensions: []
132
+ extra_rdoc_files: []
133
+ files:
134
+ - ".gitignore"
135
+ - Gemfile
136
+ - README.md
137
+ - Rakefile
138
+ - bin/chkdfront
139
+ - chkdfront.gemspec
140
+ - lib/chkdfront.rb
141
+ - lib/chkdfront/cli_operations.rb
142
+ - lib/chkdfront/providers.rb
143
+ - lib/chkdfront/request.rb
144
+ - lib/chkdfront/troubleshoot.rb
145
+ - lib/chkdfront/version.rb
146
+ homepage: https://github.com/KINGSABRI/chkdfront
147
+ licenses:
148
+ - MIT
149
+ metadata:
150
+ source_code_uri: https://github.com/KINGSABRI/chkdfront
151
+ bug_tracker_uri: https://github.com/KINGSABRI/chkdfront/issues
152
+ post_install_message:
153
+ rdoc_options: []
154
+ require_paths:
155
+ - lib
156
+ required_ruby_version: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ required_rubygems_version: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ requirements: []
167
+ rubygems_version: 3.0.2
168
+ signing_key:
169
+ specification_version: 4
170
+ summary: Check Domain Fronting (chkdfront) - It checks if domain fronting is working.
171
+ test_files: []