nslookupot 0.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: '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