passivedns-client 2.1.6 → 2.1.12
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 +5 -5
- data/.gitignore +0 -0
- data/Gemfile +0 -0
- data/LICENSE.txt +0 -0
- data/README.md +3 -0
- data/lib/passivedns/client.rb +77 -37
- data/lib/passivedns/client/cli.rb +149 -141
- data/lib/passivedns/client/passivedb.rb +0 -0
- data/lib/passivedns/client/provider/bfk.rb +56 -52
- data/lib/passivedns/client/provider/circl.rb +55 -39
- data/lib/passivedns/client/provider/cn360.rb +44 -33
- data/lib/passivedns/client/provider/dnsdb.rb +57 -56
- data/lib/passivedns/client/provider/mnemonic.rb +63 -55
- data/lib/passivedns/client/provider/passivetotal.rb +48 -43
- data/lib/passivedns/client/provider/riskiq.rb +59 -43
- data/lib/passivedns/client/provider/tcpiputils.rb +20 -19
- data/lib/passivedns/client/provider/virustotal.rb +60 -46
- data/lib/passivedns/client/state.rb +237 -236
- data/lib/passivedns/client/version.rb +1 -1
- data/passivedns-client.gemspec +6 -6
- data/test/helper.rb +0 -0
- data/test/test_cli.rb +34 -5
- data/test/test_passivedns-client.rb +153 -146
- metadata +23 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d8ea3feed82ed9f049ef8d7cd6ac78c087b94a630449cdbb3560fc28364ffe41
|
4
|
+
data.tar.gz: 37056ad39c2d721a3b5e6ee9f0347c5f1f79686f75eb15da99e2f155fc7b22d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 61ca76c52991e1a9e131d51412f0a855301b9555cbd0d1d6e5fe9c0071c1bc2d0b1539926148c090ad31c7db1aaff544565537c4db2f59bfd449e6747786d655
|
7
|
+
data.tar.gz: 4bae5d3265ca1723c9170dc3e1ec726a6d855ff2324b4744692f0a9a486444751723fa907ce50ef9960900fa4236b53fdfb1484f04fc4a91c7dc1e6d61889756
|
data/.gitignore
CHANGED
File without changes
|
data/Gemfile
CHANGED
File without changes
|
data/LICENSE.txt
CHANGED
File without changes
|
data/README.md
CHANGED
@@ -115,6 +115,9 @@ Or use the included tool...
|
|
115
115
|
-r# specifies the levels of recursion to pull. **WARNING** This is quite taxing on the pDNS servers, so use judiciously (never more than 3 or so) or find yourself blocked!
|
116
116
|
-w# specifies the amount of time to wait, in seconds, between queries (Default: 0)
|
117
117
|
-l <count> limits the number of records returned per passive dns database queried.
|
118
|
+
|
119
|
+
Specifying a Configuration File
|
120
|
+
--config <file> specifies a config file. default: #{ENV['HOME']}/.passivedns-client
|
118
121
|
|
119
122
|
Getting Help
|
120
123
|
-v debugging information
|
data/lib/passivedns/client.rb
CHANGED
@@ -12,22 +12,56 @@ provider_path = File.dirname(__FILE__)+"/client/provider/*.rb"
|
|
12
12
|
Dir.glob(provider_path).each do |provider|
|
13
13
|
name = File.basename(provider, '.rb')
|
14
14
|
require "passivedns/client/provider/#{name}.rb"
|
15
|
-
|
15
|
+
if name != 'bfk'
|
16
|
+
$passivedns_providers << name
|
17
|
+
end
|
16
18
|
end
|
17
19
|
|
18
20
|
require 'configparser'
|
19
21
|
|
20
22
|
module PassiveDNS # :nodoc:
|
23
|
+
|
24
|
+
class SecurityControl
|
25
|
+
def allow(user_level)
|
26
|
+
raise "unimplemented"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class TLPSecurityControl < SecurityControl
|
31
|
+
LEVELS = ['white','green','yellow','red']
|
32
|
+
|
33
|
+
def initialize(tlp)
|
34
|
+
if tlp =~ /(white|green|yellow|red)/i
|
35
|
+
@tlp = tlp.downcase
|
36
|
+
@tlp_level = LEVELS.index(@tlp)
|
37
|
+
else
|
38
|
+
raise "Unknown TLP setting, #{tlp}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def allow(user_level)
|
43
|
+
user_level = LEVELS.index(user_level.downcase)
|
44
|
+
if user_level == nil
|
45
|
+
raise "Invalid user level, #{user_level}"
|
46
|
+
end
|
47
|
+
return(user_level >= @tlp_level)
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_s()
|
51
|
+
@tlp
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
21
55
|
# struct to contain the results from a PassiveDNS lookup
|
22
|
-
|
56
|
+
class PDNSResult < Struct.new(:source, :response_time, :query, :answer, :rrtype, :ttl, :firstseen, :lastseen, :count, :security); end
|
23
57
|
|
24
58
|
# coodinates the lookups accross all configured PassiveDNS providers
|
25
|
-
|
59
|
+
class Client
|
26
60
|
|
27
61
|
# instantiate and configure all specified PassiveDNS providers
|
28
62
|
# pdns array of passivedns provider names, e.g., ["dnsdb","virustotal"]
|
29
63
|
# configfile filename of the passivedns-client configuration (this should probably be abstracted)
|
30
|
-
|
64
|
+
def initialize(pdns=$passivedns_providers, configfile="#{ENV['HOME']}/.passivedns-client")
|
31
65
|
cp = {}
|
32
66
|
if File.exist?(configfile)
|
33
67
|
cp = ConfigParser.new(configfile)
|
@@ -42,7 +76,7 @@ module PassiveDNS # :nodoc:
|
|
42
76
|
end
|
43
77
|
end
|
44
78
|
|
45
|
-
|
79
|
+
@pdnsdbs = []
|
46
80
|
pdns.uniq.each do |pd|
|
47
81
|
if class_map[pd]
|
48
82
|
@pdnsdbs << class_map[pd].new(cp[pd] || {})
|
@@ -51,38 +85,44 @@ module PassiveDNS # :nodoc:
|
|
51
85
|
end
|
52
86
|
end
|
53
87
|
|
54
|
-
|
55
|
-
|
88
|
+
end #initialize
|
89
|
+
|
56
90
|
# set the debug flag
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
91
|
+
def debug=(d)
|
92
|
+
@pdnsdbs.each do |pdnsdb|
|
93
|
+
pdnsdb.debug = d
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def timeout=(t)
|
98
|
+
@pdnsdbs.each do |pdnsdb|
|
99
|
+
pdnsdb.timeout = t
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
63
103
|
# perform the query lookup accross all configured PassiveDNS providers
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
104
|
+
def query(item, limit=nil)
|
105
|
+
threads = []
|
106
|
+
@pdnsdbs.each do |pdnsdb|
|
107
|
+
threads << Thread.new(item) do |q|
|
108
|
+
pdnsdb.lookup(q, limit)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
results = []
|
113
|
+
threads.each do |thr|
|
114
|
+
rv = thr.join.value
|
115
|
+
if rv
|
116
|
+
rv.each do |r|
|
117
|
+
if ["A","AAAA","NS","CNAME","PTR"].index(r.rrtype)
|
118
|
+
results << r
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
return results
|
125
|
+
end #query
|
126
|
+
|
127
|
+
end # Client
|
88
128
|
end # PassiveDNS
|
@@ -7,7 +7,7 @@ require 'pp'
|
|
7
7
|
module PassiveDNS # :nodoc:
|
8
8
|
# Handles all the command-line parsing, state tracking, and dispatching queries to the PassiveDNS::Client instance
|
9
9
|
# CLInterface is aliased by CLI
|
10
|
-
|
10
|
+
class CLInterface
|
11
11
|
# generates a mapping between the option letter for each PassiveDNS provider and the class
|
12
12
|
def self.get_letter_map
|
13
13
|
letter_map = {}
|
@@ -41,24 +41,25 @@ module PassiveDNS # :nodoc:
|
|
41
41
|
origARGV = ARGV.dup
|
42
42
|
ARGV.replace(args)
|
43
43
|
opts = GetoptLong.new(
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
44
|
+
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
|
45
|
+
[ '--debug', '-v', GetoptLong::NO_ARGUMENT ],
|
46
|
+
[ '--database', '-d', GetoptLong::REQUIRED_ARGUMENT ],
|
47
|
+
|
48
|
+
[ '--gdf', '-g', GetoptLong::NO_ARGUMENT ],
|
49
|
+
[ '--graphviz', '-z', GetoptLong::NO_ARGUMENT ],
|
50
|
+
[ '--graphml', '-m', GetoptLong::NO_ARGUMENT ],
|
51
|
+
[ '--csv', '-c', GetoptLong::NO_ARGUMENT ],
|
52
|
+
[ '--xml', '-x', GetoptLong::NO_ARGUMENT ],
|
53
|
+
[ '--yaml', '-y', GetoptLong::NO_ARGUMENT ],
|
54
|
+
[ '--json', '-j', GetoptLong::NO_ARGUMENT ],
|
55
|
+
[ '--text', '-t', GetoptLong::NO_ARGUMENT ],
|
56
|
+
[ '--sep', '-s', GetoptLong::REQUIRED_ARGUMENT ],
|
57
|
+
|
58
|
+
[ '--sqlite3', '-f', GetoptLong::REQUIRED_ARGUMENT ],
|
59
|
+
[ '--recurse', '-r', GetoptLong::REQUIRED_ARGUMENT ],
|
60
|
+
[ '--wait', '-w', GetoptLong::REQUIRED_ARGUMENT ],
|
61
|
+
[ '--limit', '-l', GetoptLong::REQUIRED_ARGUMENT ],
|
62
|
+
[ '--config', GetoptLong::REQUIRED_ARGUMENT ]
|
62
63
|
)
|
63
64
|
|
64
65
|
letter_map = get_letter_map
|
@@ -74,17 +75,18 @@ module PassiveDNS # :nodoc:
|
|
74
75
|
:debug => false,
|
75
76
|
:sqlitedb => nil,
|
76
77
|
:limit => nil,
|
77
|
-
:help => false
|
78
|
+
:help => false,
|
79
|
+
:configfile => "#{ENV['HOME']}/.passivedns-client"
|
78
80
|
}
|
79
81
|
|
80
82
|
opts.each do |opt, arg|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
83
|
+
case opt
|
84
|
+
when '--help'
|
85
|
+
options[:help] = true
|
86
|
+
when '--debug'
|
87
|
+
options[:debug] = true
|
88
|
+
when '--database'
|
89
|
+
arg.split(//).each do |c|
|
88
90
|
if c == ','
|
89
91
|
next
|
90
92
|
elsif letter_map[c]
|
@@ -94,60 +96,62 @@ module PassiveDNS # :nodoc:
|
|
94
96
|
usage(letter_map)
|
95
97
|
end
|
96
98
|
end
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
99
|
+
when '--gdf'
|
100
|
+
options[:format] = 'gdf'
|
101
|
+
when '--graphviz'
|
102
|
+
options[:format] = 'graphviz'
|
103
|
+
when '--graphml'
|
104
|
+
options[:format] = 'graphml'
|
105
|
+
when '--csv'
|
106
|
+
options[:format] = 'text'
|
107
|
+
options[:sep] = ','
|
108
|
+
when '--yaml'
|
109
|
+
options[:format] = 'yaml'
|
110
|
+
when '--xml'
|
111
|
+
options[:format] = 'xml'
|
112
|
+
when '--json'
|
113
|
+
options[:format] = 'json'
|
114
|
+
when '--text'
|
115
|
+
options[:format] = 'text'
|
116
|
+
when '--sep'
|
117
|
+
options[:sep] = arg
|
118
|
+
when '--recurse'
|
119
|
+
options[:recursedepth] = arg.to_i
|
120
|
+
when '--wait'
|
121
|
+
options[:wait] = arg.to_i
|
122
|
+
when '--sqlite3'
|
123
|
+
options[:sqlitedb] = arg
|
124
|
+
when '--limit'
|
125
|
+
options[:limit] = arg.to_i
|
126
|
+
when '--config'
|
127
|
+
options[:configfile] = arg
|
128
|
+
else
|
129
|
+
options[:help] = true
|
130
|
+
end
|
127
131
|
end
|
128
132
|
args = ARGV.dup
|
129
133
|
ARGV.replace(origARGV)
|
130
134
|
|
131
135
|
if options[:pdnsdbs].length == 0
|
132
|
-
|
136
|
+
options[:pdnsdbs] << "bfk"
|
133
137
|
end
|
134
138
|
|
135
139
|
if options[:pdnsdbs].index("bfk") and options[:recursedepth] > 1 and options[:wait] < 60
|
136
|
-
|
137
|
-
|
140
|
+
options[:wait] = 60
|
141
|
+
$stderr.puts "Enforcing a minimal 60 second wait when using BFK for recursive crawling"
|
138
142
|
end
|
139
143
|
|
140
144
|
if options[:debug]
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
145
|
+
$stderr.puts "Using the following databases: #{options[:pdnsdbs].join(", ")}"
|
146
|
+
$stderr.puts "Recursions: #{options[:recursedepth]}, Wait time: #{options[:wait]}, Limit: #{options[:limit] or 'none'}"
|
147
|
+
if options[:format] == "text" or options[:format] == "csv"
|
148
|
+
$stderr.puts "Output format: #{options[:format]} (sep=\"#{options[:sep]}\")"
|
149
|
+
else
|
150
|
+
$stderr.puts "Output format: #{options[:format]}"
|
151
|
+
end
|
152
|
+
if ENV['http_proxy']
|
153
|
+
$stderr.puts "Using proxy settings: http_proxy=#{ENV['http_proxy']}, https_proxy=#{ENV['https_proxy']}"
|
154
|
+
end
|
151
155
|
end
|
152
156
|
|
153
157
|
[options, args]
|
@@ -158,36 +162,39 @@ module PassiveDNS # :nodoc:
|
|
158
162
|
def self.usage(letter_map)
|
159
163
|
databases = letter_map.keys.sort.join("")
|
160
164
|
help_text = ""
|
161
|
-
|
165
|
+
help_text << "Usage: #{$0} [-d [#{databases}]] [-g|-v|-m|-c|-x|-y|-j|-t] [-os <sep>] [-f <file>] [-r#|-w#|-v] [-l <count>] [--config <file>] <ip|domain|cidr>\n"
|
162
166
|
help_text << "Passive DNS Providers\n"
|
163
|
-
|
167
|
+
help_text << " -d#{databases} uses all of the available passive dns database\n"
|
164
168
|
letter_map.keys.sort.each do |l|
|
165
169
|
help_text << " -d#{l} use #{letter_map[l][0]}\n"
|
166
170
|
end
|
167
|
-
|
168
|
-
|
171
|
+
help_text << " -dvt uses VirusTotal and TCPIPUtils (for example)\n"
|
172
|
+
help_text << "\n"
|
169
173
|
help_text << "Output Formatting\n"
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
174
|
+
help_text << " -g link-nodal GDF visualization definition\n"
|
175
|
+
help_text << " -z link-nodal graphviz visualization definition\n"
|
176
|
+
help_text << " -m link-nodal graphml visualization definition\n"
|
177
|
+
help_text << " -c CSV\n"
|
178
|
+
help_text << " -x XML\n"
|
179
|
+
help_text << " -y YAML\n"
|
180
|
+
help_text << " -j JSON\n"
|
181
|
+
help_text << " -t ASCII text (default)\n"
|
182
|
+
help_text << " -s <sep> specifies a field separator for text output, default is tab\n"
|
183
|
+
help_text << "\n"
|
180
184
|
help_text << "State and Recursion\n"
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
185
|
+
help_text << " -f[file] specifies a sqlite3 database used to read the current state - useful for large result sets and generating graphs of previous runs.\n"
|
186
|
+
help_text << " -r# specifies the levels of recursion to pull. **WARNING** This is quite taxing on the pDNS servers, so use judiciously (never more than 3 or so) or find yourself blocked!\n"
|
187
|
+
help_text << " -w# specifies the amount of time to wait, in seconds, between queries (Default: 0)\n"
|
188
|
+
help_text << " -l <count> limits the number of records returned per passive dns database queried.\n"
|
189
|
+
help_text << "\n"
|
190
|
+
help_text << "Specifying a Configuration File\n"
|
191
|
+
help_text << " --config <file> specifies a config file. default: #{ENV['HOME']}/.passivedns-client\n"
|
192
|
+
help_text << "\n"
|
186
193
|
help_text << "Getting Help\n"
|
187
194
|
help_text << " -h hello there. This option produces this helpful help information on how to access help.\n"
|
188
|
-
|
195
|
+
help_text << " -v debugging information\n"
|
189
196
|
|
190
|
-
|
197
|
+
help_text
|
191
198
|
end
|
192
199
|
|
193
200
|
# performs a stateful, recursive (if desired) passive DNS lookup against all specified providers
|
@@ -196,59 +203,60 @@ module PassiveDNS # :nodoc:
|
|
196
203
|
wait = options[:wait]
|
197
204
|
debug = options[:debug]
|
198
205
|
limit = options[:limit]
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
206
|
+
puts "pdnslookup: #{state.level} #{recursedepth}" if debug
|
207
|
+
level = 0
|
208
|
+
while level < recursedepth
|
209
|
+
puts "pdnslookup: #{level} < #{recursedepth}" if debug
|
210
|
+
state.each_query(recursedepth) do |q|
|
211
|
+
rv = pdnsclient.query(q,limit)
|
212
|
+
if rv
|
213
|
+
rv.each do |r|
|
214
|
+
if ["A","AAAA","NS","CNAME","PTR"].index(r.rrtype)
|
215
|
+
puts "pdnslookup: #{r.to_s}" if debug
|
216
|
+
state.add_result(r)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
else
|
220
|
+
state.update_query(rv,'failed')
|
221
|
+
end
|
222
|
+
sleep wait if level < recursedepth
|
223
|
+
end
|
224
|
+
level += 1
|
225
|
+
end
|
226
|
+
state
|
220
227
|
end
|
221
228
|
|
222
229
|
# returns a string transforming all the PassiveDNS::PDNSResult stored in the state object into text/xml/json/etc.
|
223
230
|
def self.results_to_s(state,options)
|
224
231
|
format = options[:format]
|
225
232
|
sep = options[:sep]
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
233
|
+
case format
|
234
|
+
when 'text'
|
235
|
+
PassiveDNS::PDNSResult.members.join(sep)+"\n"+state.to_s(sep)
|
236
|
+
when 'yaml'
|
237
|
+
state.to_yaml
|
238
|
+
when 'xml'
|
239
|
+
state.to_xml
|
240
|
+
when 'json'
|
241
|
+
state.to_json
|
242
|
+
when 'gdf'
|
243
|
+
state.to_gdf
|
244
|
+
when 'graphviz'
|
245
|
+
state.to_graphviz
|
246
|
+
when 'graphml'
|
247
|
+
state.to_graphml
|
248
|
+
end
|
242
249
|
end
|
243
250
|
|
244
251
|
# create a state instance
|
245
252
|
def self.create_state(sqlitedb=nil)
|
246
253
|
state = nil
|
247
254
|
if sqlitedb
|
248
|
-
|
255
|
+
state = PassiveDNS::PDNSToolStateDB.new(sqlitedb)
|
249
256
|
else
|
250
|
-
|
257
|
+
state = PassiveDNS::PDNSToolState.new
|
251
258
|
end
|
259
|
+
state
|
252
260
|
end
|
253
261
|
|
254
262
|
# main method, takes command-line arguments and performs the desired queries and outputs
|
@@ -257,24 +265,24 @@ module PassiveDNS # :nodoc:
|
|
257
265
|
if options[:help]
|
258
266
|
return usage(get_letter_map)
|
259
267
|
end
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
268
|
+
if options[:recursedepth] > 3
|
269
|
+
$stderr.puts "WARNING: a recursedepth of > 3 can be abusive, please reconsider: sleeping 60 seconds for sense to come to you (hint: hit CTRL-C)"
|
270
|
+
sleep 60
|
271
|
+
end
|
264
272
|
state = create_state(options[:sqlitedb])
|
265
273
|
state.debug = options[:debug]
|
266
274
|
|
267
|
-
pdnsclient = PassiveDNS::Client.new(options[:pdnsdbs])
|
275
|
+
pdnsclient = PassiveDNS::Client.new(options[:pdnsdbs], options[:configfile])
|
268
276
|
pdnsclient.debug = options[:debug]
|
269
277
|
|
270
278
|
if items.length > 0
|
271
|
-
|
272
|
-
|
273
|
-
|
279
|
+
items.each do |arg|
|
280
|
+
state.add_query(arg,'pending',0)
|
281
|
+
end
|
274
282
|
else
|
275
|
-
|
276
|
-
|
277
|
-
|
283
|
+
$stdin.each_line do |l|
|
284
|
+
state.add_query(l.chomp,'pending',0)
|
285
|
+
end
|
278
286
|
end
|
279
287
|
pdnslookup(state,pdnsclient,options)
|
280
288
|
results_to_s(state,options)
|