onion 0.1.1 → 0.1.2

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.
@@ -1,22 +1,5 @@
1
- = Onion
2
-
3
- == Introduction
4
-
5
- Onion is a library for interacting with Tor. Onion is in an alpha state and is
6
- made availible for early adopters and contributors only.
7
-
8
- == Functionality
9
-
10
- * Parse router status entries per the directory protocol version 2.0.
11
-
12
- == Authors
13
-
14
- Onion was written by Tim Sally <poet@stack.io>. Please send bug reports and
15
- suggestions to the author.
16
-
17
- == License
18
-
19
- (The MIT License)
1
+ LICENSE.txt
2
+ ===========
20
3
 
21
4
  Copyright (c) 2010 Tim Sally
22
5
 
@@ -0,0 +1,34 @@
1
+ README.txt
2
+ ==========
3
+
4
+ Introduction
5
+ ------------
6
+
7
+ Onion is a library for interacting with Tor. Onion is in an alpha state and is
8
+ made available for early adopters and contributors only.
9
+
10
+ Basic Concepts
11
+ --------------
12
+
13
+ Elements are pieces of the Tor network. Routers, circuits, and streams are
14
+ examples of elements. You don't care about how the library gets these, you
15
+ just want to be able to interact with them. Methods in the Control Client
16
+ return elements.
17
+
18
+ Parsers take information received from Tor and turn the information into
19
+ elements. Parsers are used internally by the Control Client to create elements
20
+ to return to the user.
21
+
22
+ The Control Client is what you can use in scripts to interact with Tor.
23
+
24
+ Authors
25
+ -------
26
+
27
+ Onion was written by Tim Sally <poet@stack.io>. Please send bug reports and
28
+ suggestions to the author.
29
+
30
+ License
31
+ -------
32
+
33
+ Copyright (c) 2010 Tim Sally and provided under the MIT License. Please see
34
+ LICENSE.txt for details.
@@ -1,8 +1,8 @@
1
1
  module Onion
2
-
2
+ require 'onion/control_client'
3
3
  require 'onion/elements'
4
4
 
5
- parsers = %w[ router_lists ]
5
+ parsers = %w[ common circuit_lists router_statuses stream_lists ]
6
6
  parsers.each do |parser|
7
7
  begin
8
8
  # If there is a pre-compiled parser, load it.
@@ -0,0 +1,87 @@
1
+ require 'logger'
2
+ require 'socket'
3
+
4
+ module Onion
5
+ # Onion::ControlClient is a client to the Tor Control Protocol.
6
+ class ControlClient
7
+ attr_reader :host, :port
8
+
9
+ def initialize(host="127.0.0.1", port=9051, log_level=Logger::ERROR)
10
+ @log = Logger.new(STDOUT)
11
+ @log.level = log_level
12
+
13
+ @host = host # Host of the Tor process.
14
+ @port = port # Port accepting the Tor Control Protocol.
15
+ @sock = TCPSocket.new(host, port)
16
+
17
+ @log.info("[TOR CONTROL CLIENT ] Connected to #{host}:#{port}.")
18
+ end
19
+
20
+ def send(text)
21
+ @sock << "#{text}\r\n"
22
+ @log.debug("[TOR CONTROL CLIENT] #{text}")
23
+ end
24
+
25
+ def authenticate(pass="\"\"")
26
+ send("authenticate #{pass}")
27
+ @log.debug("[TOR CONTROL CLIENT] #{@sock.gets}")
28
+ end
29
+
30
+ def extend_circuit(specs, id=0)
31
+ send("extendcircuit #{id} #{specs.join(",")}")
32
+ response = @sock.gets
33
+ if response.split[1] == "EXTENDED"
34
+ @log.debug("[TOR CONTROL CLIENT] #{response}")
35
+ return response.split[2]
36
+ else
37
+ @log.warn("[TOR CONTROL CLIENT] Circuit (#{specs.join(",")}) was not extended.")
38
+ @log.warn("[TOR CONTROL CLIENT] #{response}.")
39
+
40
+ return -1
41
+ end
42
+ end
43
+
44
+ def attach_stream(stream_id, circuit_id)
45
+ send("attachstream #{stream_id} #{circuit_id}")
46
+ response = @sock.gets
47
+ if response.split[1] == "OK"
48
+ @log.info("[TOR CONTROL CLIENT] #{response}")
49
+ else
50
+ @log.warn("[TOR CONTROL CLIENT] Stream #{stream_id} was not attached to circuit #{circuit_id}.")
51
+ @log.warn("[TOR CONTROL CLIENT] #{response}.")
52
+ end
53
+ end
54
+
55
+ def router_status_info(nicknames=nil,fingerprints=nil)
56
+ statuses = ""
57
+
58
+ p "start!"
59
+
60
+ if nicknames
61
+ nicknames.each do |name|
62
+ send("getinfo ns/name/#{name}")
63
+ statuses << @sock.gets
64
+ end
65
+ while not @sock.eof?
66
+ statuses << @sock.gets
67
+ end
68
+ end
69
+ p "done!"
70
+ Onion::RouterList.new(statuses)
71
+ end
72
+
73
+ def get_stream_status
74
+ send("getinfo stream-status")
75
+ result = []
76
+ line = @sock.gets
77
+ while line != "250 OK\r\n"
78
+ unless line == "250+stream-status=\r\n" or line == ".\r\n"
79
+ line = line.gsub("250-stream-status=", "")
80
+ result << line
81
+ end
82
+ line = @sock.gets
83
+ end
84
+ return result
85
+ end
86
+ end
87
+ end
@@ -1,4 +1,8 @@
1
1
  module Onion
2
+ autoload :Circuit, 'onion/elements/circuit'
3
+ autoload :CircuitList, 'onion/elements/circuit_list'
2
4
  autoload :Router, 'onion/elements/router'
3
5
  autoload :RouterList, 'onion/elements/router_list'
6
+ autoload :Stream, 'onion/elements/stream'
7
+ autoload :StreamList, 'onion/elements/stream_list'
4
8
  end
@@ -0,0 +1,11 @@
1
+ module Onion
2
+ # Onion::Circuit is an object representing a Tor circuit.
3
+ class Circuit
4
+ attr_reader :id, :routers
5
+
6
+ def initialize(id, routers)
7
+ @id = id
8
+ @routers = routers
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ module Onion
2
+ # Onion::CircuitList is a list of Onion::Circuit objects.
3
+ class CircuitList
4
+ attr_reader :circuits
5
+ def initialize(text)
6
+ if text.blank?
7
+ @circuits = []
8
+ return self
9
+ end
10
+ parser = Onion::CircuitListsParser.new
11
+ if nodes = parser.parse(text)
12
+ @circuits = nodes.circuits
13
+ else
14
+ raise Exception, "Couldn't parse #{text} b/c #{parser.failure_reason}."
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,10 +1,10 @@
1
1
  module Onion
2
2
  # Onion::Router is a Ruby object representing a Tor router.
3
3
  class Router
4
- attr_reader :nick, :id_key_hash, :status_flags
5
- def initialize(nick, id_key_hash, status_flags)
4
+ attr_reader :nick, :fingerprint, :status_flags
5
+ def initialize(nick, fingerprint, status_flags)
6
6
  @nick = nick # Nickname of the router.
7
- @id_key_hash = id_key_hash # Hash of the router identity key.
7
+ @fingerprint = fingerprint # Fingerprint of the router.
8
8
  @status_flags = status_flags # Array of strings with status flags.
9
9
  end
10
10
 
@@ -1,7 +1,5 @@
1
1
  module Onion
2
- # Onion::RouterList is a list of Onion::Router objects. On initialization,
3
- # the text given is parsed with Onion::RouterListParser. The text should be
4
- # in the router status format specified by the directory protocol 2.0 spec.
2
+ # Onion::RouterList is a list of Onion::Router objects.
5
3
  class RouterList
6
4
  attr_reader :routers
7
5
  def initialize(text)
@@ -9,11 +7,11 @@ module Onion
9
7
  @routers = []
10
8
  return self
11
9
  end
12
- parser = Onion::RouterListsParser.new
10
+ parser = Onion::RouterStatusesParser.new
13
11
  if nodes = parser.parse(text)
14
12
  @routers = nodes.routers
15
13
  else
16
- raise Exception "Couldn't parse #{text} b/c #{parser.failure_reason}."
14
+ raise Exception, "Couldn't parse #{text} b/c #{parser.failure_reason}."
17
15
  end
18
16
  end
19
17
 
@@ -29,7 +27,7 @@ module Onion
29
27
 
30
28
  # Returns the routers that are neither guard or exit routers.
31
29
  def middlemen
32
- @routers.filter { |r| r.guard? or r.exit? }
30
+ @routers.reject { |r| r.guard? or r.exit? }
33
31
  end
34
32
  end
35
33
  end
@@ -0,0 +1,12 @@
1
+ module Onion
2
+ # Onion::Circuit is an object representing a Tor stream.
3
+ class Stream
4
+ attr_reader :stream_id, :circuit_id
5
+
6
+ def initialize(stream_id, circuit_id)
7
+ @stream_id = stream_id
8
+ @circuit_id = circuit_id
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,20 @@
1
+ module Onion
2
+ # Onion::StreamList is a list of Onion::Stream objects.
3
+ class StreamList
4
+ attr_reader :streams
5
+ def initialize(text)
6
+ if text.blank?
7
+ @streams = []
8
+ return self
9
+ end
10
+
11
+ parser = Onion::StreamListsParser.new
12
+ if nodes = parser.parse(text)
13
+ @streams = nodes.streams
14
+ else
15
+ raise Exception, "Couldn't parse #{text} b/c #{parser.failure_reason}."
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,491 @@
1
+ # Autogenerated from a Treetop grammar. Edits may be lost.
2
+
3
+
4
+ module Onion
5
+ module CircuitLists
6
+ include Treetop::Runtime
7
+
8
+ def root
9
+ @root ||= :circuit_list
10
+ end
11
+
12
+ include Common
13
+
14
+ module CircuitList0
15
+ def circuits
16
+ circuits = []
17
+ self.elements.each do |circuit|
18
+ if circuit.respond_to? :p
19
+ to_process = [circuit.p.first]
20
+ counter = 1
21
+ circuit.p.rest.elements.each do |e|
22
+ to_process << e.LongName
23
+ end
24
+ routers = []
25
+ to_process.each do |router|
26
+ if router.respond_to? :n
27
+ routers << Router.new(router.n.text_value.strip, router.f.text_value.strip, nil)
28
+ else
29
+ routers << Router.new(nil, nil, nil)
30
+ end
31
+ end
32
+ circuits << Circuit.new(circuit.id.text_value.strip, routers)
33
+ else
34
+ circuits << Circuit.new(circuit.id.text_value.strip, [])
35
+ end
36
+ end
37
+ return circuits
38
+ end
39
+ end
40
+
41
+ def _nt_circuit_list
42
+ start_index = index
43
+ if node_cache[:circuit_list].has_key?(index)
44
+ cached = node_cache[:circuit_list][index]
45
+ if cached
46
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
47
+ @index = cached.interval.end
48
+ end
49
+ return cached
50
+ end
51
+
52
+ s0, i0 = [], index
53
+ loop do
54
+ r1 = _nt_circuit_list_entry
55
+ if r1
56
+ s0 << r1
57
+ else
58
+ break
59
+ end
60
+ end
61
+ if s0.empty?
62
+ @index = i0
63
+ r0 = nil
64
+ else
65
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
66
+ r0.extend(CircuitList0)
67
+ end
68
+
69
+ node_cache[:circuit_list][start_index] = r0
70
+
71
+ r0
72
+ end
73
+
74
+ module CircuitListEntry0
75
+ def id
76
+ elements[0]
77
+ end
78
+
79
+ def SP1
80
+ elements[1]
81
+ end
82
+
83
+ def s
84
+ elements[2]
85
+ end
86
+
87
+ def SP2
88
+ elements[3]
89
+ end
90
+
91
+ def p
92
+ elements[4]
93
+ end
94
+
95
+ def SP3
96
+ elements[5]
97
+ end
98
+
99
+ def purp
100
+ elements[7]
101
+ end
102
+
103
+ end
104
+
105
+ module CircuitListEntry1
106
+ def id
107
+ elements[0]
108
+ end
109
+
110
+ def SP1
111
+ elements[1]
112
+ end
113
+
114
+ def s
115
+ elements[2]
116
+ end
117
+
118
+ def SP2
119
+ elements[3]
120
+ end
121
+
122
+ def p
123
+ elements[4]
124
+ end
125
+
126
+ end
127
+
128
+ module CircuitListEntry2
129
+ def id
130
+ elements[0]
131
+ end
132
+
133
+ def SP
134
+ elements[1]
135
+ end
136
+
137
+ def s
138
+ elements[2]
139
+ end
140
+
141
+ end
142
+
143
+ def _nt_circuit_list_entry
144
+ start_index = index
145
+ if node_cache[:circuit_list_entry].has_key?(index)
146
+ cached = node_cache[:circuit_list_entry][index]
147
+ if cached
148
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
149
+ @index = cached.interval.end
150
+ end
151
+ return cached
152
+ end
153
+
154
+ i0 = index
155
+ i1, s1 = index, []
156
+ r2 = _nt_CircuitID
157
+ s1 << r2
158
+ if r2
159
+ r3 = _nt_SP
160
+ s1 << r3
161
+ if r3
162
+ r4 = _nt_CircStatus
163
+ s1 << r4
164
+ if r4
165
+ r5 = _nt_SP
166
+ s1 << r5
167
+ if r5
168
+ r6 = _nt_Path
169
+ s1 << r6
170
+ if r6
171
+ r7 = _nt_SP
172
+ s1 << r7
173
+ if r7
174
+ if has_terminal?("PURPOSE=", false, index)
175
+ r8 = instantiate_node(SyntaxNode,input, index...(index + 8))
176
+ @index += 8
177
+ else
178
+ terminal_parse_failure("PURPOSE=")
179
+ r8 = nil
180
+ end
181
+ s1 << r8
182
+ if r8
183
+ r9 = _nt_Purpose
184
+ s1 << r9
185
+ if r9
186
+ if has_terminal?("\n", false, index)
187
+ r10 = instantiate_node(SyntaxNode,input, index...(index + 1))
188
+ @index += 1
189
+ else
190
+ terminal_parse_failure("\n")
191
+ r10 = nil
192
+ end
193
+ s1 << r10
194
+ end
195
+ end
196
+ end
197
+ end
198
+ end
199
+ end
200
+ end
201
+ end
202
+ if s1.last
203
+ r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
204
+ r1.extend(CircuitListEntry0)
205
+ else
206
+ @index = i1
207
+ r1 = nil
208
+ end
209
+ if r1
210
+ r0 = r1
211
+ else
212
+ i11, s11 = index, []
213
+ r12 = _nt_CircuitID
214
+ s11 << r12
215
+ if r12
216
+ r13 = _nt_SP
217
+ s11 << r13
218
+ if r13
219
+ r14 = _nt_CircStatus
220
+ s11 << r14
221
+ if r14
222
+ r15 = _nt_SP
223
+ s11 << r15
224
+ if r15
225
+ r16 = _nt_Path
226
+ s11 << r16
227
+ if r16
228
+ if has_terminal?("\n", false, index)
229
+ r17 = instantiate_node(SyntaxNode,input, index...(index + 1))
230
+ @index += 1
231
+ else
232
+ terminal_parse_failure("\n")
233
+ r17 = nil
234
+ end
235
+ s11 << r17
236
+ end
237
+ end
238
+ end
239
+ end
240
+ end
241
+ if s11.last
242
+ r11 = instantiate_node(SyntaxNode,input, i11...index, s11)
243
+ r11.extend(CircuitListEntry1)
244
+ else
245
+ @index = i11
246
+ r11 = nil
247
+ end
248
+ if r11
249
+ r0 = r11
250
+ else
251
+ i18, s18 = index, []
252
+ r19 = _nt_CircuitID
253
+ s18 << r19
254
+ if r19
255
+ r20 = _nt_SP
256
+ s18 << r20
257
+ if r20
258
+ r21 = _nt_CircStatus
259
+ s18 << r21
260
+ if r21
261
+ if has_terminal?("\n", false, index)
262
+ r22 = instantiate_node(SyntaxNode,input, index...(index + 1))
263
+ @index += 1
264
+ else
265
+ terminal_parse_failure("\n")
266
+ r22 = nil
267
+ end
268
+ s18 << r22
269
+ end
270
+ end
271
+ end
272
+ if s18.last
273
+ r18 = instantiate_node(SyntaxNode,input, i18...index, s18)
274
+ r18.extend(CircuitListEntry2)
275
+ else
276
+ @index = i18
277
+ r18 = nil
278
+ end
279
+ if r18
280
+ r0 = r18
281
+ else
282
+ @index = i0
283
+ r0 = nil
284
+ end
285
+ end
286
+ end
287
+
288
+ node_cache[:circuit_list_entry][start_index] = r0
289
+
290
+ r0
291
+ end
292
+
293
+ module Path0
294
+ def LongName
295
+ elements[1]
296
+ end
297
+ end
298
+
299
+ module Path1
300
+ def first
301
+ elements[0]
302
+ end
303
+
304
+ def rest
305
+ elements[1]
306
+ end
307
+ end
308
+
309
+ def _nt_Path
310
+ start_index = index
311
+ if node_cache[:Path].has_key?(index)
312
+ cached = node_cache[:Path][index]
313
+ if cached
314
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
315
+ @index = cached.interval.end
316
+ end
317
+ return cached
318
+ end
319
+
320
+ i0, s0 = index, []
321
+ r1 = _nt_LongName
322
+ s0 << r1
323
+ if r1
324
+ s2, i2 = [], index
325
+ loop do
326
+ i3, s3 = index, []
327
+ if has_terminal?(",", false, index)
328
+ r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
329
+ @index += 1
330
+ else
331
+ terminal_parse_failure(",")
332
+ r4 = nil
333
+ end
334
+ s3 << r4
335
+ if r4
336
+ r5 = _nt_LongName
337
+ s3 << r5
338
+ end
339
+ if s3.last
340
+ r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
341
+ r3.extend(Path0)
342
+ else
343
+ @index = i3
344
+ r3 = nil
345
+ end
346
+ if r3
347
+ s2 << r3
348
+ else
349
+ break
350
+ end
351
+ end
352
+ r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
353
+ s0 << r2
354
+ end
355
+ if s0.last
356
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
357
+ r0.extend(Path1)
358
+ else
359
+ @index = i0
360
+ r0 = nil
361
+ end
362
+
363
+ node_cache[:Path][start_index] = r0
364
+
365
+ r0
366
+ end
367
+
368
+ def _nt_CircStatus
369
+ start_index = index
370
+ if node_cache[:CircStatus].has_key?(index)
371
+ cached = node_cache[:CircStatus][index]
372
+ if cached
373
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
374
+ @index = cached.interval.end
375
+ end
376
+ return cached
377
+ end
378
+
379
+ i0 = index
380
+ if has_terminal?("LAUNCHED", false, index)
381
+ r1 = instantiate_node(SyntaxNode,input, index...(index + 8))
382
+ @index += 8
383
+ else
384
+ terminal_parse_failure("LAUNCHED")
385
+ r1 = nil
386
+ end
387
+ if r1
388
+ r0 = r1
389
+ else
390
+ if has_terminal?("BUILT", false, index)
391
+ r2 = instantiate_node(SyntaxNode,input, index...(index + 5))
392
+ @index += 5
393
+ else
394
+ terminal_parse_failure("BUILT")
395
+ r2 = nil
396
+ end
397
+ if r2
398
+ r0 = r2
399
+ else
400
+ if has_terminal?("EXTENDED", false, index)
401
+ r3 = instantiate_node(SyntaxNode,input, index...(index + 8))
402
+ @index += 8
403
+ else
404
+ terminal_parse_failure("EXTENDED")
405
+ r3 = nil
406
+ end
407
+ if r3
408
+ r0 = r3
409
+ else
410
+ if has_terminal?("FAILED", false, index)
411
+ r4 = instantiate_node(SyntaxNode,input, index...(index + 6))
412
+ @index += 6
413
+ else
414
+ terminal_parse_failure("FAILED")
415
+ r4 = nil
416
+ end
417
+ if r4
418
+ r0 = r4
419
+ else
420
+ if has_terminal?("CLOSED", false, index)
421
+ r5 = instantiate_node(SyntaxNode,input, index...(index + 6))
422
+ @index += 6
423
+ else
424
+ terminal_parse_failure("CLOSED")
425
+ r5 = nil
426
+ end
427
+ if r5
428
+ r0 = r5
429
+ else
430
+ @index = i0
431
+ r0 = nil
432
+ end
433
+ end
434
+ end
435
+ end
436
+ end
437
+
438
+ node_cache[:CircStatus][start_index] = r0
439
+
440
+ r0
441
+ end
442
+
443
+ def _nt_Purpose
444
+ start_index = index
445
+ if node_cache[:Purpose].has_key?(index)
446
+ cached = node_cache[:Purpose][index]
447
+ if cached
448
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
449
+ @index = cached.interval.end
450
+ end
451
+ return cached
452
+ end
453
+
454
+ i0 = index
455
+ if has_terminal?("GENERAL", false, index)
456
+ r1 = instantiate_node(SyntaxNode,input, index...(index + 7))
457
+ @index += 7
458
+ else
459
+ terminal_parse_failure("GENERAL")
460
+ r1 = nil
461
+ end
462
+ if r1
463
+ r0 = r1
464
+ else
465
+ if has_terminal?("CONTROLER", false, index)
466
+ r2 = instantiate_node(SyntaxNode,input, index...(index + 9))
467
+ @index += 9
468
+ else
469
+ terminal_parse_failure("CONTROLER")
470
+ r2 = nil
471
+ end
472
+ if r2
473
+ r0 = r2
474
+ else
475
+ @index = i0
476
+ r0 = nil
477
+ end
478
+ end
479
+
480
+ node_cache[:Purpose][start_index] = r0
481
+
482
+ r0
483
+ end
484
+
485
+ end
486
+
487
+ class CircuitListsParser < Treetop::Runtime::CompiledParser
488
+ include CircuitLists
489
+ end
490
+
491
+ end