nslookupot 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '0846a02a74eb40953b233d52b2b8f38f12414f8b3bf9c06c7eb2603129100428'
4
+ data.tar.gz: ab65aa27f3980d3bad019c6711258111da627298a3a07e63deb781550dda7ed3
5
+ SHA512:
6
+ metadata.gz: 4ef75c8b9bd0b4acebec3255714f853a1b777f2e0132d9018dd094b5ff394e063439e68dc9f60621558964e5f73e4a0d2b332978b33078b54c29513f50ca94fd
7
+ data.tar.gz: aa3653f20ebd41e739f9d7aa7c24356ad037b6d333aed83da6f8d7c9b33d82f39c50a516229cb547222b3e309bc309543dc51ad21d7d6f05c9c41d84a9fad7b2
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ *.gem
2
+ /vendor/
3
+ /pkg/
4
+ /spec/reports/
5
+ /spec/examples.txt
6
+ /tmp/
7
+
8
+ .byebug_history
9
+ /.bundle/
10
+ /vendor/bundle
11
+ /lib/bundler/man/
12
+
13
+ Gemfile.lock
14
+ .ruby-version
15
+ .ruby-gemset
16
+ .rvmrc
data/.rubocop.yml ADDED
@@ -0,0 +1,20 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.6
3
+
4
+ Style/Documentation:
5
+ Enabled: false
6
+
7
+ Style/NumericLiterals:
8
+ Enabled: false
9
+
10
+ Style/BlockDelimiters:
11
+ Enabled: false
12
+
13
+ Metrics/AbcSize:
14
+ Max: 30
15
+
16
+ Metrics/MethodLength:
17
+ Max: 30
18
+
19
+ Naming/UncommunicativeMethodParamName:
20
+ MinNameLength: 1
data/.travis.yml ADDED
@@ -0,0 +1,17 @@
1
+ sudo: false
2
+
3
+ language: ruby
4
+
5
+ rvm:
6
+ - 2.6.3
7
+ - ruby-head
8
+
9
+ matrix:
10
+ allow_failures:
11
+ - rvm: ruby-head
12
+
13
+ before_install:
14
+ - gem install bundler
15
+ - bundle install
16
+
17
+ script: bundle exec rake
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gem 'openssl'
6
+ gem 'rake'
7
+
8
+ group :test do
9
+ gem 'pry'
10
+ gem 'pry-byebug'
11
+ gem 'rspec', '3.8.0'
12
+ gem 'rubocop', '0.68.1'
13
+ end
14
+
15
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Tomoya Kuwayama
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # nslookupot
2
+
3
+ [![Build Status](https://travis-ci.org/thekuwayama/nslookupot.svg?branch=master)](https://travis-ci.org/thekuwayama/nslookupot)
4
+ [![Maintainability](https://api.codeclimate.com/v1/badges/5df9157757f5a0bf1623/maintainability)](https://codeclimate.com/github/thekuwayama/nslookupot/maintainability)
5
+
6
+ nslookupot is CLI that is `nslookup` over TLS (version 1.2).
7
+
8
+
9
+ ## Installation
10
+
11
+ The gem is available at [rubygems.org](https://rubygems.org/gems/nslookupot). You can install with:
12
+
13
+ ```bash
14
+ $ gem install nslookupot
15
+ ```
16
+
17
+
18
+ ## Usage
19
+
20
+ ```bash
21
+ $ nslookupot --help
22
+ Usage: nslookupot [options] name
23
+ -s, --server VALUE the name server IP address (default 1.1.1.1)
24
+ -p, --port VALUE the name server port number (default 853)
25
+ -h, --hostname VALUE the name server hostname (default cloudflare-dns.com)
26
+ -t, --type VALUE the type of the information query (default A)
27
+ ```
28
+
29
+ You can run it the following:
30
+
31
+ ```bash
32
+ $ nslookupot example.com
33
+ Address: 1.1.1.1#853
34
+ --
35
+ Name: example.com
36
+ Address: 93.184.216.34
37
+ Ttl: 2860
38
+
39
+ ```
40
+
41
+ If you need to resolve other than A type, you can run it the following:
42
+
43
+ ```bash
44
+ $ nslookupot --type=cname www.youtube.com
45
+ Address: 1.1.1.1#853
46
+ --
47
+ Name: www.youtube.com
48
+ Name: youtube-ui.l.google.com
49
+ Ttl: 1358
50
+
51
+ ```
52
+
53
+ If you need to query to `8.8.8.8`, you can run it the following:
54
+
55
+ ```bash
56
+ $ nslookupot --server=8.8.8.8 --port=853 --hostname=dns.google www.google.com
57
+ Address: 8.8.8.8#853
58
+ --
59
+ Name: www.google.com
60
+ Address: 172.217.24.132
61
+ Ttl: 223
62
+
63
+ ```
64
+
65
+ If you need to query to `9.9.9.9`, you can run it the following:
66
+
67
+ ```bash
68
+ $ nslookupot --server=9.9.9.9 --port=853 --hostname=quad9.net www.quad9.net
69
+ Address: 9.9.9.9#853
70
+ --
71
+ Name: www.quad9.net
72
+ Address: 216.21.3.77
73
+ Ttl: 1200
74
+
75
+ ```
76
+
77
+
78
+ ## License
79
+
80
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rubocop/rake_task'
5
+ require 'rspec/core/rake_task'
6
+
7
+ RuboCop::RakeTask.new
8
+ RSpec::Core::RakeTask.new(:spec)
9
+
10
+ task default: %i[rubocop spec]
data/exe/nslookupot ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ $LOAD_PATH << __dir__ + '/../lib'
5
+
6
+ require 'nslookupot'
7
+
8
+ Nslookupot::CLI.new.run
data/lib/nslookupot.rb ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'resolv'
4
+ require 'socket'
5
+ require 'openssl'
6
+ require 'optparse'
7
+
8
+ require 'nslookupot/version'
9
+ require 'nslookupot/resolver'
10
+ require 'nslookupot/cli'
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'optparse'
4
+
5
+ module Nslookupot
6
+ class CLI
7
+ # rubocop: disable Metrics/MethodLength
8
+ def parse_options(argv = ARGV)
9
+ op = OptionParser.new
10
+
11
+ # default value
12
+ opts = {
13
+ server: '1.1.1.1',
14
+ port: 853,
15
+ hostname: 'cloudflare-dns.com'
16
+ }
17
+ type = 'A'
18
+
19
+ op.on(
20
+ '-s',
21
+ '--server VALUE',
22
+ "the name server IP address (default #{opts[:server]})"
23
+ ) do |v|
24
+ opts[:server] = v
25
+ end
26
+
27
+ op.on(
28
+ '-p',
29
+ '--port VALUE',
30
+ "the name server port number (default #{opts[:port]})"
31
+ ) do |v|
32
+ opts[:port] = v
33
+ end
34
+
35
+ op.on(
36
+ '-h',
37
+ '--hostname VALUE',
38
+ "the name server hostname (default #{opts[:hostname]})"
39
+ ) do |v|
40
+ opts[:hostname] = v
41
+ end
42
+
43
+ op.on(
44
+ '-t',
45
+ '--type VALUE',
46
+ "the type of the information query (default #{type})"
47
+ ) do |v|
48
+ type = v
49
+ end
50
+
51
+ op.banner += ' name'
52
+ begin
53
+ args = op.parse(argv)
54
+ rescue OptionParser::InvalidOption => e
55
+ puts op.to_s
56
+ puts "error: #{e.message}"
57
+ exit 1
58
+ end
59
+
60
+ begin
61
+ type = s2typeclass(type)
62
+ rescue NameError
63
+ puts "error: unknown query type #{type}"
64
+ exit 1
65
+ end
66
+
67
+ if args.size != 1
68
+ puts op.to_s
69
+ puts 'error: number of arguments is not 1'
70
+ exit 1
71
+ end
72
+
73
+ [opts, args[0], type]
74
+ end
75
+ # rubocop: enable Metrics/MethodLength
76
+
77
+ def s2typeclass(s)
78
+ Resolv::DNS::Resource::IN.const_get(s.upcase)
79
+ end
80
+
81
+ def run
82
+ opts, name, type = parse_options
83
+
84
+ resolver = Nslookupot::Resolver.new(opts)
85
+ puts 'Address:'.ljust(16) + opts[:server] + '#' + opts[:port].to_s
86
+ puts '--'
87
+ resolver.resolve_resources(name, type).each do |rr|
88
+ puts 'Name:'.ljust(16) + name
89
+ rr.instance_variables.each do |v|
90
+ k = (v[1..].capitalize + ':').ljust(16)
91
+ v = rr.instance_variable_get(v).to_s
92
+ puts k + v
93
+ end
94
+ puts ''
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nslookupot
4
+ class Resolver
5
+ # @param server [String]
6
+ # @param port [Integer]
7
+ # @param hostname [String]
8
+ def initialize(server: '1.1.1.1', port: 853,
9
+ hostname: 'cloudflare-dns.com')
10
+ @server = server
11
+ @port = port
12
+ @hostname = hostname # for SNI
13
+ end
14
+
15
+ # @param name [String]
16
+ #
17
+ # @return [Resolv::IPv4 | Resolv::IPv6]
18
+ def resolve_address(name)
19
+ resolve_resources(name, Resolv::DNS::Resource::IN::A).first.address
20
+ end
21
+
22
+ # @param name [String]
23
+ #
24
+ # @return [Array of Resolv::IPv4 | Resolv::IPv6]
25
+ def resolve_addresses(name)
26
+ resolve_resources(name, Resolv::DNS::Resource::IN::A).map(&:address)
27
+ end
28
+
29
+ # @param name [String]
30
+ # @param typeclass [Resolv::DNS::Resource::IN constant]
31
+ #
32
+ # @return [Array of Resolv::DNS::Resource]
33
+ def resolve_resources(name, typeclass)
34
+ sock = gen_sock
35
+ send_msg(sock, name, typeclass)
36
+ msg = recv_msg(sock)
37
+ sock.close
38
+
39
+ msg.answer.map(&:last)
40
+ end
41
+
42
+ private
43
+
44
+ # @param sock [OpenSSL::SSL::SSLSocket]
45
+ #
46
+ # @return [Resolv::DNS::Message]
47
+ def recv_msg(sock)
48
+ # The message is prefixed with a two byte length field which gives the
49
+ # message length, excluding the two byte length field.
50
+ #
51
+ # https://tools.ietf.org/html/rfc1035#section-4.2.2
52
+ l = sock.read(2).unpack1('n')
53
+
54
+ Resolv::DNS::Message.decode(sock.read(l))
55
+ end
56
+
57
+ # @param sock [OpenSSL::SSL::SSLSocket]
58
+ # @param name [String]
59
+ # @param typeclass [Resolv::DNS::Resource::IN constant]
60
+ def send_msg(sock, name, typeclass)
61
+ q = Resolv::DNS::Message.new
62
+ q.rd = 1 # recursion desired
63
+ q.add_question(name, typeclass)
64
+ # The message is prefixed with a two byte length field
65
+ message = [q.encode.length].pack('n') + q.encode
66
+ sock.write(message)
67
+ end
68
+
69
+ # @return [OpenSSL::SSL::SSLSocket]
70
+ def gen_sock
71
+ ts = TCPSocket.new(@server, @port)
72
+ ctx = OpenSSL::SSL::SSLContext.new('TLSv1_2')
73
+ sock = OpenSSL::SSL::SSLSocket.new(ts, ctx)
74
+ sock.sync_close = true
75
+ sock.connect
76
+ sock.post_connection_check(@hostname)
77
+
78
+ sock
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nslookupot
4
+ VERSION = '0.0.1'
5
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'nslookupot/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'nslookupot'
9
+ spec.version = Nslookupot::VERSION
10
+ spec.authors = ['thekuwayama']
11
+ spec.email = ['thekuwayama@gmail.com']
12
+ spec.summary = 'nslookup over TLS'
13
+ spec.description = spec.summary
14
+ spec.homepage = 'https://github.com/thekuwayama/nslookupot'
15
+ spec.license = 'MIT'
16
+ spec.required_ruby_version = '>=2.6.0'
17
+
18
+ spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ['lib']
21
+ spec.bindir = 'exe'
22
+ spec.executables = ['nslookupot']
23
+
24
+ spec.add_development_dependency 'bundler'
25
+ spec.add_dependency 'openssl'
26
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'spec_helper'
5
+
6
+ RSpec.describe Nslookupot::Resolver do
7
+ context '(DNS over TLS)' do
8
+ let(:resolver) do
9
+ Nslookupot::Resolver.new
10
+ end
11
+
12
+ let(:sock) do
13
+ sock = SimpleStream.new
14
+ bin = "\x00\x2d\x00\x00\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\x07\x65" \
15
+ "\x78\x61\x6d\x70\x6c\x65\x03\x63\x6f\x6d\x00\x00\x01\x00\x01\xc0" \
16
+ "\x0c\x00\x01\x00\x01\x00\x01\x18\xb3\x00\x04\x5d\xb8\xd8\x22"
17
+ sock.write(bin)
18
+
19
+ sock
20
+ end
21
+
22
+ it 'could resolve `example.com` with #getaddress' do
23
+ allow(resolver).to receive(:gen_sock).and_return(sock)
24
+ allow(resolver).to receive(:send_msg)
25
+
26
+ expect(resolver.resolve_address('example.com'))
27
+ .to eq Resolv::IPv4.create('93.184.216.34')
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.configure(&:disable_monkey_patching!)
4
+
5
+ require 'nslookupot'
6
+
7
+ class SimpleStream
8
+ def initialize(binary = '')
9
+ @buffer = binary
10
+ end
11
+
12
+ def write(binary)
13
+ @buffer += binary
14
+ end
15
+
16
+ def read(len = @buffer.length)
17
+ res = @buffer.slice(0, len)
18
+ @buffer = @buffer[len..]
19
+ res
20
+ end
21
+
22
+ def close
23
+ @buffer = nil
24
+ end
25
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nslookupot
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - thekuwayama
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-07-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
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: openssl
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
+ description: nslookup over TLS
42
+ email:
43
+ - thekuwayama@gmail.com
44
+ executables:
45
+ - nslookupot
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".gitignore"
50
+ - ".rubocop.yml"
51
+ - ".travis.yml"
52
+ - Gemfile
53
+ - LICENSE.txt
54
+ - README.md
55
+ - Rakefile
56
+ - exe/nslookupot
57
+ - lib/nslookupot.rb
58
+ - lib/nslookupot/cli.rb
59
+ - lib/nslookupot/resolver.rb
60
+ - lib/nslookupot/version.rb
61
+ - nslookupot.gemspec
62
+ - spec/resolver_spec.rb
63
+ - spec/spec_helper.rb
64
+ homepage: https://github.com/thekuwayama/nslookupot
65
+ licenses:
66
+ - MIT
67
+ metadata: {}
68
+ post_install_message:
69
+ rdoc_options: []
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: 2.6.0
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubygems_version: 3.0.3
84
+ signing_key:
85
+ specification_version: 4
86
+ summary: nslookup over TLS
87
+ test_files:
88
+ - spec/resolver_spec.rb
89
+ - spec/spec_helper.rb