Skip to content

Commit 78e4bb5

Browse files
committed
Add ASN tests and pry. Update .gitignore.
1 parent 8b84995 commit 78e4bb5

File tree

3 files changed

+341
-0
lines changed

3 files changed

+341
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@
1111
*.log
1212
*.swp
1313
*~
14+
.gem

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,5 @@ group :development do
7474
gem 'stackprof', require: false, platform: :mri
7575
gem 'rubocop', require: false, platform: :mri
7676
gem 'rubocop-ronin', require: false, platform: :mri
77+
gem 'pry', require: false
7778
end

spec/cli/commands/asn_spec.rb

Lines changed: 339 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,346 @@
11
require 'spec_helper'
22
require 'ronin/cli/commands/asn'
33
require_relative 'man_page_example'
4+
require 'ronin/support/network/asn/list'
5+
require 'ronin/support/cli/printing'
6+
require 'tempfile'
47

58
describe Ronin::CLI::Commands::Asn do
69
include_examples "man_page"
10+
11+
subject { described_class.new }
12+
13+
let(:ip2asn_truncated) do
14+
<<~TSV
15+
223.255.233.0\t223.255.233.255\t140694\tAU\tARAFURA-AS-AP Northern Technology Solutions
16+
223.255.234.0\t223.255.234.255\t0\tNone\tNot routed
17+
223.255.235.0\t223.255.235.255\t140694\tAU\tARAFURA-AS-AP Northern Technology Solutions
18+
223.255.236.0\t223.255.239.255\t56000\tCN\tHERBALIFE-CNDC HERBALIFESHANGHAIMANAGEMENT CO.,LTD.
19+
223.255.240.0\t223.255.243.255\t55649\tHK\tMETRONET-HK Flat C, 16F, Skyline Tower
20+
223.255.244.0\t223.255.247.255\t45117\tIN\tINPL-IN-AP Ishans Network
21+
223.255.248.0\t223.255.251.255\t63199\tUS\tCDSC-AS1
22+
223.255.252.0\t223.255.253.255\t58519\tCN\tCHINATELECOM-CTCLOUD Cloud Computing Corporation
23+
223.255.254.0\t223.255.254.255\t55415\tSG\tMBS-SG 4 Shenton Way
24+
::\t::1\t0\tNone\tNot routed
25+
64:ff9b::1:0:0\t100::ffff:ffff:ffff:ffff\t0\tNone\tNot routed
26+
100:0:0:1::\t2001:0:ffff:ffff:ffff:ffff:ffff:ffff\t0\tNone\tNot routed
27+
2001:1::\t2001:4:111:ffff:ffff:ffff:ffff:ffff\t0\tNone\tNot routed
28+
2001:4:112::\t2001:4:112:ffff:ffff:ffff:ffff:ffff\t112\tUS\t-Reserved AS-
29+
2001:4:113::\t2001:1ff:ffff:ffff:ffff:ffff:ffff:ffff\t0\tNone\tNot routed
30+
2001:200::\t2001:200:5ff:ffff:ffff:ffff:ffff:ffff\t2500\tJP\tWIDE-BB WIDE Project
31+
2001:200:600::\t2001:200:6ff:ffff:ffff:ffff:ffff:ffff\t7667\tJP\tKDDLAB KDDI R&D Laboratories, INC.
32+
2001:200:700::\t2001:200:8ff:ffff:ffff:ffff:ffff:ffff\t2500\tJP\tWIDE-BB WIDE Project
33+
2001:200:900::\t2001:200:9ff:ffff:ffff:ffff:ffff:ffff\t7660\tJP\tAPAN-JP Asia Pacific Advanced Network - Japan
34+
2001:200:a00::\t2001:200:dff:ffff:ffff:ffff:ffff:ffff\t2500\tJP\tWIDE-BB WIDE Project
35+
TSV
36+
end
37+
38+
let(:ip2asn_file) do
39+
Tempfile.new.tap do |file|
40+
file.write(ip2asn_truncated)
41+
file.rewind
42+
end
43+
end
44+
45+
after do
46+
ip2asn_file.close
47+
ip2asn_file.unlink
48+
end
49+
50+
describe '#run?' do
51+
context "when the file does not exist" do
52+
before do
53+
subject.options[:file] = 'nonexistent_file'
54+
allow(subject).to receive(:download)
55+
allow(subject).to receive(:print_asn_records)
56+
end
57+
58+
it 'calls #download' do
59+
expect(subject).to receive(:download)
60+
subject.run
61+
end
62+
end
63+
64+
context "when options[:update] is true" do
65+
before do
66+
subject.options[:update] = true
67+
allow(subject).to receive(:update)
68+
allow(subject).to receive(:print_asn_records)
69+
end
70+
71+
it 'calls #update' do
72+
expect(subject).to receive(:update)
73+
subject.run
74+
end
75+
end
76+
77+
context "when the file is stale" do
78+
before do
79+
allow(Ronin::Support::Network::ASN::List).to receive(:stale?).and_return(true)
80+
allow(subject).to receive(:update)
81+
allow(subject).to receive(:print_asn_records)
82+
end
83+
84+
it 'calls #update' do
85+
expect(subject).to receive(:update)
86+
subject.run
87+
end
88+
end
89+
90+
context "when given default options and an IP address" do
91+
before do
92+
subject.options[:ip] = '223.255.233.1'
93+
allow(subject).to receive(:query_ip).and_return(true)
94+
allow(subject).to receive(:print_asn_record)
95+
end
96+
97+
it "calls #print_asn_record" do
98+
expect(subject).to receive(:print_asn_record)
99+
subject.run
100+
end
101+
end
102+
103+
# FIXME (cmhobbs) the use of #exit has caused this to be difficult to test
104+
pending "when given default options and an invalid IP address"
105+
# context "when given default options and an invalid IP address" do
106+
# before do
107+
# subject.options[:ip] = 'invalid'
108+
# allow(subject).to receive(:query_ip).and_return(false)
109+
# allow(subject).to receive(:exit)
110+
# end
111+
112+
# it "calls print_error" do
113+
# error_message = "could not find a record for the IP: invalid"
114+
# expect(Ronin::Support::CLI::Printing).to receive(:print_error)
115+
# #expect { subject.run }.to output(error_message)
116+
# subject.run
117+
# end
118+
# end
119+
120+
context "when given default options and no IP address" do
121+
before do
122+
allow(subject).to receive(:update)
123+
end
124+
125+
it "calls print_asn_records" do
126+
expect(subject).to receive(:print_asn_records)
127+
subject.run
128+
end
129+
end
130+
end
131+
132+
describe '#stale?' do
133+
let(:file) { 'file' }
134+
135+
before do
136+
subject.options[:file] = file
137+
end
138+
139+
it 'calls Support::Network::ASN::List.stale? with the file' do
140+
expect(Ronin::Support::Network::ASN::List).to receive(:stale?).with(file)
141+
subject.stale?
142+
end
143+
end
144+
145+
describe '#download' do
146+
context "with default parameters" do
147+
let(:url) { 'https://iptoasn.com/data/ip2asn-combined.tsv.gz' }
148+
let(:file) { "#{Dir.home}/.cache/ronin/ronin-support/ip2asn-combined.tsv.gz" }
149+
150+
it 'calls Support::Network::ASN::List.download with default parameters' do
151+
expect(Ronin::Support::Network::ASN::List).to receive(:download).with(
152+
url: url,
153+
path: file
154+
)
155+
subject.download
156+
end
157+
end
158+
159+
context "with optional parameters" do
160+
let(:url) { 'http://example.com' }
161+
let(:file) { 'file' }
162+
163+
before do
164+
subject.options[:url] = url
165+
subject.options[:file] = file
166+
end
167+
168+
it 'calls Support::Network::ASN::List.download with optional parameters' do
169+
expect(Ronin::Support::Network::ASN::List).to receive(:download).with(
170+
url: url,
171+
path: file
172+
)
173+
subject.download
174+
end
175+
end
176+
end
177+
178+
describe "#update" do
179+
context "with default parameters" do
180+
let(:url) { 'https://iptoasn.com/data/ip2asn-combined.tsv.gz' }
181+
let(:file) { "#{Dir.home}/.cache/ronin/ronin-support/ip2asn-combined.tsv.gz" }
182+
183+
it 'calls Support::Network::ASN::List.update with default parameters' do
184+
expect(Ronin::Support::Network::ASN::List).to receive(:update).with(
185+
url: url,
186+
path: file
187+
)
188+
subject.update
189+
end
190+
end
191+
192+
context "with optional parameters" do
193+
let(:url) { 'http://example.com' }
194+
let(:file) { 'file' }
195+
196+
before do
197+
subject.options[:url] = url
198+
subject.options[:file] = file
199+
end
200+
201+
it 'calls Support::Network::ASN::List.update with optional parameters' do
202+
expect(Ronin::Support::Network::ASN::List).to receive(:update).with(
203+
url: url,
204+
path: file
205+
)
206+
subject.update
207+
end
208+
end
209+
end
210+
211+
describe "#list_file" do
212+
let(:file) { 'file' }
213+
214+
before do
215+
subject.options[:file] = file
216+
end
217+
218+
it 'calls Support::Network::ASN::List.parse' do
219+
expect(Ronin::Support::Network::ASN::List).to receive(:parse).with(file)
220+
subject.list_file
221+
end
222+
end
223+
224+
describe "#query_ip" do
225+
let(:ip) { '127.0.0.1' }
226+
227+
it 'calls Support::Network::ASN::List.query_ip' do
228+
expect(Ronin::Support::Network::ASN).to receive(:query).with(ip)
229+
subject.query_ip(ip)
230+
end
231+
end
232+
233+
describe "#search_asn_records" do
234+
before do
235+
subject.options[:file] = ip2asn_file.path
236+
end
237+
238+
context "given the ipv4 option" do
239+
it "returns the ipv4 records" do
240+
subject.options[:ipv4] = true
241+
records = subject.search_asn_records
242+
expect(records).to be_a(Ronin::Support::Network::ASN::RecordSet)
243+
expect(records.to_a.length).to eq(9)
244+
end
245+
end
246+
247+
context "given the ipv6 option" do
248+
it "returns the ipv6 records" do
249+
subject.options[:ipv6] = true
250+
records = subject.search_asn_records
251+
expect(records).to be_a(Ronin::Support::Network::ASN::RecordSet)
252+
expect(records.to_a.length).to eq(11)
253+
end
254+
end
255+
256+
context "given a country code" do
257+
it "returns the records for the country code" do
258+
subject.options[:country_code] = 'JP'
259+
records = subject.search_asn_records
260+
expect(records).to be_a(Ronin::Support::Network::ASN::RecordSet)
261+
expect(records.to_a.length).to eq(5)
262+
end
263+
end
264+
265+
context "given an ASN number" do
266+
it "returns the records for the ASN number" do
267+
subject.options[:number] = 140694
268+
records = subject.search_asn_records
269+
expect(records).to be_a(Ronin::Support::Network::ASN::RecordSet)
270+
expect(records.to_a.length).to eq(2)
271+
end
272+
end
273+
274+
context "given an ASN name" do
275+
it "returns the records for the ASN name" do
276+
subject.options[:name] = 'WIDE-BB WIDE Project'
277+
records = subject.search_asn_records
278+
expect(records).to be_a(Ronin::Support::Network::ASN::RecordSet)
279+
expect(records.to_a.length).to eq(3)
280+
end
281+
end
282+
end
283+
284+
describe "#print_asn_records" do
285+
before do
286+
subject.options[:file] = ip2asn_file.path
287+
end
288+
289+
it "calls #print_asn_record for each record" do
290+
records = subject.search_asn_records
291+
292+
expect(subject).to receive(:print_asn_record).exactly(20).times
293+
subject.print_asn_records(records)
294+
end
295+
end
296+
297+
describe "#print_asn_record" do
298+
context "with the enum_ips option" do
299+
before do
300+
subject.options[:enum_ips] = true
301+
subject.options[:file] = ip2asn_file.path
302+
end
303+
304+
it "prints each IP address in the range" do
305+
record = subject.search_asn_records.first
306+
307+
# NOTE: we're not testing output here due to the large number of IPs
308+
expect(record.range).to receive(:each)
309+
subject.print_asn_record(record)
310+
end
311+
end
312+
313+
context "with the verbose option set" do
314+
before do
315+
subject.options[:verbose] = true
316+
subject.options[:file] = ip2asn_file.path
317+
end
318+
319+
it "prints the record in verbose format" do
320+
record = subject.search_asn_records.first
321+
322+
output(
323+
"[ AS140694 ]\n\n" \
324+
"ASN: 140694\n" \
325+
"IP range: 223.255.233.0 - 223.255.233.255\n" \
326+
"Country: AU\n" \
327+
"Name: ARAFURA-AS-AP Northern Technology Solutions\n\n"
328+
).to_stdout
329+
end
330+
end
331+
332+
context "with default options" do
333+
before do
334+
subject.options[:file] = ip2asn_file.path
335+
end
336+
337+
it "prints the record in default format" do
338+
record = subject.search_asn_records.first
339+
340+
expect { subject.print_asn_record(record) }.to output(
341+
"223.255.233.0 - 223.255.233.255 AS140694\ (AU) ARAFURA-AS-AP Northern Technology Solutions\n"
342+
).to_stdout
343+
end
344+
end
345+
end
7346
end

0 commit comments

Comments
 (0)