i2p 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +1 -0
- data/CONTRIBUTORS +0 -0
- data/README +155 -0
- data/UNLICENSE +24 -0
- data/VERSION +1 -0
- data/lib/i2p.rb +177 -0
- data/lib/i2p/bob.rb +27 -0
- data/lib/i2p/bob/client.rb +489 -0
- data/lib/i2p/bob/tunnel.rb +303 -0
- data/lib/i2p/data/certificate.rb +75 -0
- data/lib/i2p/data/destination.rb +68 -0
- data/lib/i2p/data/key.rb +40 -0
- data/lib/i2p/data/key_pair.rb +65 -0
- data/lib/i2p/data/private_key.rb +14 -0
- data/lib/i2p/data/public_key.rb +14 -0
- data/lib/i2p/data/signing_private_key.rb +10 -0
- data/lib/i2p/data/signing_public_key.rb +10 -0
- data/lib/i2p/data/structure.rb +84 -0
- data/lib/i2p/hosts.rb +207 -0
- data/lib/i2p/sam.rb +40 -0
- data/lib/i2p/sam/client.rb +226 -0
- data/lib/i2p/sdk.jar +0 -0
- data/lib/i2p/sdk.rb +111 -0
- data/lib/i2p/streaming.jar +0 -0
- data/lib/i2p/streaming.rb +10 -0
- data/lib/i2p/version.rb +22 -0
- metadata +116 -0
@@ -0,0 +1,303 @@
|
|
1
|
+
module I2P; module BOB
|
2
|
+
##
|
3
|
+
# **I2P Basic Open Bridge (BOB) tunnel manager.**
|
4
|
+
#
|
5
|
+
# @example Creating and controlling a new tunnel
|
6
|
+
# I2P::BOB::Tunnel.new(...) do |tunnel|
|
7
|
+
# tunnel.start
|
8
|
+
# sleep 0.1 until tunnel.running?
|
9
|
+
# # ... code that uses the tunnel goes here ...
|
10
|
+
# tunnel.stop
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# @example Starting a new inbound I2P tunnel in one go
|
14
|
+
# I2P::BOB::Tunnel.start({
|
15
|
+
# :nickname => :inproxy,
|
16
|
+
# :inhost => "127.0.0.1"
|
17
|
+
# :inport => 12345, # unused port
|
18
|
+
# })
|
19
|
+
#
|
20
|
+
# @example Starting a new outbound I2P tunnel in one go
|
21
|
+
# I2P::BOB::Tunnel.start({
|
22
|
+
# :nickname => :myssh,
|
23
|
+
# :outhost => "127.0.0.1",
|
24
|
+
# :outport => 22, # SSH port
|
25
|
+
# })
|
26
|
+
#
|
27
|
+
# @example Starting an existing tunnel
|
28
|
+
# I2P::BOB::Tunnel.start(:myssh)
|
29
|
+
#
|
30
|
+
# @example Obtaining the I2P destination for a tunnel
|
31
|
+
# tunnel = I2P::BOB::Tunnel.start(:mytunnel)
|
32
|
+
# tunnel.destination #=> #<I2P::Destination:...>
|
33
|
+
#
|
34
|
+
# @example Stopping an existing tunnel
|
35
|
+
# I2P::BOB::Tunnel.stop(:myssh)
|
36
|
+
#
|
37
|
+
# @see http://www.i2p2.de/applications.html
|
38
|
+
# @see http://bob.i2p.to/bridge.html
|
39
|
+
# @since 0.1.4
|
40
|
+
class Tunnel
|
41
|
+
##
|
42
|
+
# Starts up a new tunnel.
|
43
|
+
#
|
44
|
+
# @param [Hash{Symbol => Object}] options
|
45
|
+
# @option options [String, #to_s] :nickname (Time.now.to_i)
|
46
|
+
# @option options [KeyPair, #to_s] :keys (nil)
|
47
|
+
# @option options [Boolean] :quiet (false)
|
48
|
+
# @option options [String, #to_s] :inhost ("localhost")
|
49
|
+
# @option options [Integer, #to_i] :inport (nil)
|
50
|
+
# @option options [String, #to_s] :outhost ("localhost")
|
51
|
+
# @option options [Integer, #to_i] :outport (nil)
|
52
|
+
# @return [Tunnel]
|
53
|
+
def self.start(options = {}, &block)
|
54
|
+
tunnel = self.new(options).start
|
55
|
+
|
56
|
+
if block_given?
|
57
|
+
begin
|
58
|
+
result = block.call(tunnel)
|
59
|
+
ensure
|
60
|
+
tunnel.stop
|
61
|
+
end
|
62
|
+
result
|
63
|
+
else
|
64
|
+
tunnel
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# Shuts down an existing tunnel of the given `nickname`.
|
70
|
+
#
|
71
|
+
# @param [String, #to_s]
|
72
|
+
# @return [void]
|
73
|
+
def self.stop(nickname)
|
74
|
+
self.new(nickname).stop
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# Initializes a new tunnel instance.
|
79
|
+
#
|
80
|
+
# @overload initialize(options = {})
|
81
|
+
# @param [Hash{Symbol => Object}] options
|
82
|
+
# @option options [String, #to_s] :nickname (Time.now.to_i)
|
83
|
+
# @option options [KeyPair, #to_s] :keys (nil)
|
84
|
+
# @option options [Boolean] :quiet (false)
|
85
|
+
# @option options [String, #to_s] :inhost ("localhost")
|
86
|
+
# @option options [Integer, #to_i] :inport (nil)
|
87
|
+
# @option options [String, #to_s] :outhost ("localhost")
|
88
|
+
# @option options [Integer, #to_i] :outport (nil)
|
89
|
+
#
|
90
|
+
# @overload initialize(nickname)
|
91
|
+
# @param [String, #to_s] nickname
|
92
|
+
#
|
93
|
+
def initialize(options = {})
|
94
|
+
case options
|
95
|
+
when Hash
|
96
|
+
# Create a new tunnel
|
97
|
+
@nickname = options[:nickname] || Time.now.to_i.to_s
|
98
|
+
@debug = options[:debug]
|
99
|
+
setup(options)
|
100
|
+
else
|
101
|
+
# Access an existing tunnel
|
102
|
+
@nickname = options.to_s
|
103
|
+
Client.open { |client| client.getnick(@nickname) }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# Returns the nickname for this tunnel.
|
109
|
+
#
|
110
|
+
# @return [String]
|
111
|
+
# @see Client#getnick
|
112
|
+
attr_reader :nickname
|
113
|
+
|
114
|
+
##
|
115
|
+
# Returns the I2P {I2P::Destination destination} for this tunnel.
|
116
|
+
#
|
117
|
+
# @return [Destination]
|
118
|
+
# @see Client#getdest
|
119
|
+
attr_reader :destination
|
120
|
+
def destination
|
121
|
+
@destination ||= client { getdest }
|
122
|
+
end
|
123
|
+
|
124
|
+
##
|
125
|
+
# Returns the I2P {I2P::KeyPair key pair} for this tunnel.
|
126
|
+
#
|
127
|
+
# @return [KeyPair]
|
128
|
+
# @see Client#getkeys
|
129
|
+
attr_reader :keys
|
130
|
+
def keys
|
131
|
+
@keys ||= client { getkeys }
|
132
|
+
end
|
133
|
+
|
134
|
+
##
|
135
|
+
# Returns `true` if this is an inbound tunnel.
|
136
|
+
#
|
137
|
+
# @return [Boolean]
|
138
|
+
def inbound?
|
139
|
+
!!inport
|
140
|
+
end
|
141
|
+
|
142
|
+
##
|
143
|
+
# Returns the inbound host name or IP address for this tunnel.
|
144
|
+
#
|
145
|
+
# @return [String]
|
146
|
+
# @see Client#inhost
|
147
|
+
attr_reader :inhost
|
148
|
+
def inhost
|
149
|
+
@inhost ||= begin
|
150
|
+
nil # TODO
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
##
|
155
|
+
# Returns the inbound port number for this tunnel.
|
156
|
+
#
|
157
|
+
# @return [Integer]
|
158
|
+
# @see Client#inport
|
159
|
+
attr_reader :inport
|
160
|
+
def inport
|
161
|
+
@inport ||= begin
|
162
|
+
nil # TODO
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
##
|
167
|
+
# Returns `true` if this is an outbound tunnel.
|
168
|
+
#
|
169
|
+
# @return [Boolean]
|
170
|
+
def outbound?
|
171
|
+
!!outport
|
172
|
+
end
|
173
|
+
|
174
|
+
##
|
175
|
+
# Returns the outbound host name or IP address for this tunnel.
|
176
|
+
#
|
177
|
+
# @return [String]
|
178
|
+
# @see Client#outhost
|
179
|
+
attr_reader :outhost
|
180
|
+
def outhost
|
181
|
+
@outhost ||= begin
|
182
|
+
nil # TODO
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
##
|
187
|
+
# Returns the outbound port number for this tunnel.
|
188
|
+
#
|
189
|
+
# @return [Integer]
|
190
|
+
# @see Client#outport
|
191
|
+
attr_reader :outport
|
192
|
+
def outport
|
193
|
+
@outport ||= begin
|
194
|
+
nil # TODO
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
##
|
199
|
+
# Returns `true` if quiet mode is enabled for this tunnel.
|
200
|
+
#
|
201
|
+
# This only applies to outbound tunnels and has no effect on inbound
|
202
|
+
# tunnels.
|
203
|
+
#
|
204
|
+
# @return [Boolean]
|
205
|
+
# @see Client#quiet
|
206
|
+
def quiet?
|
207
|
+
@quiet ||= begin
|
208
|
+
nil # TODO
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
##
|
213
|
+
# Registers the given tunnel `options` with the BOB bridge.
|
214
|
+
#
|
215
|
+
# @param [Hash{Symbol => Object}] options
|
216
|
+
# @return [void]
|
217
|
+
def setup(options = {})
|
218
|
+
client do |client|
|
219
|
+
if options[:keys]
|
220
|
+
client.setkeys(options[:keys])
|
221
|
+
else
|
222
|
+
begin
|
223
|
+
client.getkeys
|
224
|
+
rescue Error => e
|
225
|
+
client.newkeys
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
client.quiet(options[:quiet]) if options[:quiet]
|
230
|
+
client.inhost(options[:inhost]) if options[:inhost]
|
231
|
+
client.inport(options[:inport]) if options[:inport]
|
232
|
+
client.outhost(options[:outhost]) if options[:outhost]
|
233
|
+
client.outport(options[:outport]) if options[:outport]
|
234
|
+
end
|
235
|
+
self
|
236
|
+
end
|
237
|
+
alias_method :setup!, :setup
|
238
|
+
|
239
|
+
##
|
240
|
+
# Returns `true` if this tunnel is currently active.
|
241
|
+
#
|
242
|
+
# @return [Boolean]
|
243
|
+
def running?
|
244
|
+
true # FIXME
|
245
|
+
end
|
246
|
+
alias_method :active?, :running?
|
247
|
+
|
248
|
+
##
|
249
|
+
# Starts up this tunnel.
|
250
|
+
#
|
251
|
+
# @return [void]
|
252
|
+
# @see Client#start
|
253
|
+
def start
|
254
|
+
client { start }
|
255
|
+
self
|
256
|
+
end
|
257
|
+
alias_method :start!, :start
|
258
|
+
|
259
|
+
##
|
260
|
+
# Returns `true` if this tunnel is currently in the process of starting
|
261
|
+
# up.
|
262
|
+
#
|
263
|
+
# @return [Boolean]
|
264
|
+
def starting?
|
265
|
+
# TODO
|
266
|
+
end
|
267
|
+
|
268
|
+
##
|
269
|
+
# Shuts down this tunnel.
|
270
|
+
#
|
271
|
+
# @return [void]
|
272
|
+
# @see Client#stop
|
273
|
+
def stop
|
274
|
+
client { stop }
|
275
|
+
self
|
276
|
+
end
|
277
|
+
alias_method :stop!, :stop
|
278
|
+
|
279
|
+
##
|
280
|
+
# Returns `true` if this tunnel is currently in the process of shutting
|
281
|
+
# down.
|
282
|
+
#
|
283
|
+
# @return [Boolean]
|
284
|
+
def stopping?
|
285
|
+
# TODO
|
286
|
+
end
|
287
|
+
|
288
|
+
def socket
|
289
|
+
client.socket
|
290
|
+
end
|
291
|
+
|
292
|
+
##
|
293
|
+
# Returns a {I2P::BOB::Client} instance for accessing low-level
|
294
|
+
# information about this tunnel.
|
295
|
+
#
|
296
|
+
# @yield [client]
|
297
|
+
# @yieldparam [Client] client
|
298
|
+
# @return [Client]
|
299
|
+
def client(&block)
|
300
|
+
Client.open(:nickname => nickname, :debug => @debug, &block)
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end; end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module I2P
|
2
|
+
##
|
3
|
+
# **I2P certificate data structure.**
|
4
|
+
#
|
5
|
+
# Defines a certificate that can be attached to various I2P structures,
|
6
|
+
# such as `RouterIdentity` and `Destination`, allowing routers and clients
|
7
|
+
# to help manage denial of service attacks and the network utilization.
|
8
|
+
#
|
9
|
+
# @see http://docs.i2p2.de/core/net/i2p/data/Certificate.html
|
10
|
+
# @since 0.1.3
|
11
|
+
class Certificate < Structure
|
12
|
+
TYPE_NULL = 0 # Null certificate
|
13
|
+
TYPE_HASHCASH = 1 # Hashcash certificate
|
14
|
+
TYPE_HIDDEN = 2 # Hidden certificate
|
15
|
+
TYPE_SIGNED = 3 # Signed certificate
|
16
|
+
TYPE_MULTIPLE = 4
|
17
|
+
|
18
|
+
LENGTH_SIGNED_WITH_HASH = nil # TODO
|
19
|
+
|
20
|
+
##
|
21
|
+
# Reads a certificate from the given `input` stream.
|
22
|
+
#
|
23
|
+
# @param [IO, StringIO] input
|
24
|
+
# @return [Certificate]
|
25
|
+
def self.read(input)
|
26
|
+
type = input.read(1).unpack('c').first
|
27
|
+
length = input.read(2).unpack('n').first
|
28
|
+
payload = length.zero? ? String.new : input.read(length)
|
29
|
+
self.new(type, payload)
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# @return [Integer]
|
34
|
+
attr_accessor :type
|
35
|
+
|
36
|
+
##
|
37
|
+
# @return [String]
|
38
|
+
attr_accessor :payload
|
39
|
+
|
40
|
+
##
|
41
|
+
# Initializes a new certificate instance.
|
42
|
+
#
|
43
|
+
# @param [Integer, #to_i] type
|
44
|
+
# @param [String, #to_s] payload
|
45
|
+
def initialize(type = TYPE_NULL, payload = String.new)
|
46
|
+
@type, @payload = type.to_i, payload
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Returns the byte size of this certificate.
|
51
|
+
#
|
52
|
+
# @return [Integer]
|
53
|
+
def size
|
54
|
+
1 + 2 + (payload ? payload.size : 0)
|
55
|
+
end
|
56
|
+
alias_method :bytesize, :size
|
57
|
+
|
58
|
+
##
|
59
|
+
# Returns the binary string representation of this certificate.
|
60
|
+
#
|
61
|
+
# @return [String]
|
62
|
+
def to_s
|
63
|
+
StringIO.open do |buffer|
|
64
|
+
buffer.write([type].pack('c'))
|
65
|
+
if payload && !payload.empty?
|
66
|
+
buffer.write([payload.size].pack('n'))
|
67
|
+
buffer.write(payload.to_s)
|
68
|
+
else
|
69
|
+
buffer.write([0].pack('n'))
|
70
|
+
end
|
71
|
+
buffer.string
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module I2P
|
2
|
+
##
|
3
|
+
# **I2P destination data structure.**
|
4
|
+
#
|
5
|
+
# Defines an endpoint in the I2P network. The destination may move around
|
6
|
+
# in the network, but messages sent to the destination will reach it.
|
7
|
+
#
|
8
|
+
# @see http://docs.i2p2.de/core/net/i2p/data/Destination.html
|
9
|
+
# @since 0.1.3
|
10
|
+
class Destination < Structure
|
11
|
+
BYTESIZE = 387 # minimum
|
12
|
+
|
13
|
+
##
|
14
|
+
# Reads a destination from the given `input` stream.
|
15
|
+
#
|
16
|
+
# @param [IO, StringIO] input
|
17
|
+
# @return [Destination]
|
18
|
+
def self.read(input)
|
19
|
+
self.new(PublicKey.read(input), SigningPublicKey.read(input), Certificate.read(input))
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Initializes a new destination instance.
|
24
|
+
#
|
25
|
+
# @param [PublicKey] public_key
|
26
|
+
# @param [SigningPublicKey] signing_key
|
27
|
+
# @param [Certificate] certificate
|
28
|
+
def initialize(public_key, signing_key, certificate = Certificate.new)
|
29
|
+
@public_key = public_key
|
30
|
+
@signing_key = signing_key
|
31
|
+
@certificate = certificate
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# @return [PublicKey]
|
36
|
+
attr_accessor :public_key
|
37
|
+
|
38
|
+
##
|
39
|
+
# @return [SigningPublicKey]
|
40
|
+
attr_accessor :signing_key
|
41
|
+
|
42
|
+
##
|
43
|
+
# @return [Certificate]
|
44
|
+
attr_accessor :certificate
|
45
|
+
|
46
|
+
##
|
47
|
+
# Returns the byte size of this data structure.
|
48
|
+
#
|
49
|
+
# @return [Integer]
|
50
|
+
def size
|
51
|
+
public_key.size + signing_key.size + certificate.size
|
52
|
+
end
|
53
|
+
alias_method :bytesize, :size
|
54
|
+
|
55
|
+
##
|
56
|
+
# Returns the binary string representation of this destination.
|
57
|
+
#
|
58
|
+
# @return [String]
|
59
|
+
def to_s
|
60
|
+
StringIO.open do |buffer|
|
61
|
+
buffer.write(public_key.to_s)
|
62
|
+
buffer.write(signing_key.to_s)
|
63
|
+
buffer.write(certificate.to_s)
|
64
|
+
buffer.string
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/i2p/data/key.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module I2P
|
2
|
+
##
|
3
|
+
class Key < Structure
|
4
|
+
##
|
5
|
+
# Reads a key data structure from the given `input` stream.
|
6
|
+
#
|
7
|
+
# @param [IO, StringIO] input
|
8
|
+
# @return [Key]
|
9
|
+
def self.read(input)
|
10
|
+
self.new(input.read(const_get(:BYTESIZE)))
|
11
|
+
end
|
12
|
+
|
13
|
+
##
|
14
|
+
# @return [String]
|
15
|
+
attr_accessor :data
|
16
|
+
|
17
|
+
##
|
18
|
+
# @param [String] data
|
19
|
+
def initialize(data)
|
20
|
+
@data = data.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Returns `true` if this key is of the correct size.
|
25
|
+
#
|
26
|
+
# @return [Boolean]
|
27
|
+
# @since 0.1.3
|
28
|
+
def valid?
|
29
|
+
@data.size.eql?(self.class.const_get(:BYTESIZE))
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Returns the binary string representation of this key.
|
34
|
+
#
|
35
|
+
# @return [String]
|
36
|
+
def to_s
|
37
|
+
@data
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|