Skip to content

Commit 965cb6d

Browse files
authored
Merge pull request #61 from aarani/exitNode
Support for exit nodes
2 parents 6069c42 + 8bf755f commit 965cb6d

File tree

3 files changed

+94
-8
lines changed

3 files changed

+94
-8
lines changed
+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using System;
2+
using System.IO;
3+
using System.Threading.Tasks;
4+
5+
using NUnit.Framework;
6+
7+
using NOnion.Directory;
8+
using NOnion.Http;
9+
using NOnion.Network;
10+
11+
namespace NOnion.Tests
12+
{
13+
internal class OutsideWorldConnectionTest
14+
{
15+
[SetUp]
16+
public void Init()
17+
{
18+
TorLogger.Init(TestContext.Progress.WriteLine);
19+
}
20+
21+
/* It's possible that the router returned by GetRandomFallbackDirectory or
22+
* GetRandomRoutersForDirectoryBrowsing be inaccessable so we need to continue
23+
* retrying if an exceptions happened to make sure the issues are not related
24+
* to the router we randomly chose
25+
*/
26+
private const int TestsRetryCount = 10;
27+
28+
private async Task BrowseGoogle()
29+
{
30+
var directory = await TorDirectory.BootstrapAsync(FallbackDirectorySelector.GetRandomFallbackDirectory(), new DirectoryInfo(Path.GetTempPath()));
31+
var (guardEndPoint, guardRouter) = await directory.GetRouterAsync(RouterType.Guard);
32+
var (_, middleRouter) = await directory.GetRouterAsync(RouterType.Normal);
33+
var (_, exitRouter) = await directory.GetRouterAsync(RouterType.Exit);
34+
35+
var guard = await TorGuard.NewClientAsync(guardEndPoint);
36+
var circuit = new TorCircuit(guard);
37+
await circuit.CreateAsync(guardRouter);
38+
await circuit.ExtendAsync(middleRouter);
39+
await circuit.ExtendAsync(exitRouter);
40+
41+
TorStream stream = new TorStream(circuit);
42+
await stream.ConnectToOutsideAsync("google.com", 80);
43+
44+
TorHttpClient httpClient = new TorHttpClient(stream, "google.com");
45+
await httpClient.GetAsStringAsync("/", false);
46+
}
47+
48+
[Test]
49+
[Retry(TestsRetryCount)]
50+
public void CanBrowseGoogle()
51+
{
52+
Assert.ThrowsAsync(typeof(UnsuccessfulHttpRequestException), BrowseGoogle);
53+
}
54+
}
55+
}

NOnion/Directory/TorDirectory.fs

+4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ type RouterType =
1717
| Normal
1818
| Guard
1919
| Directory
20+
| Exit
2021

2122
type TorDirectory =
2223
private
@@ -174,6 +175,9 @@ type TorDirectory =
174175
Seq.filter(fun router ->
175176
Seq.contains "Guard" router.Flags
176177
)
178+
| Exit ->
179+
Seq.filter(fun router -> Seq.contains "Exit" router.Flags
180+
)
177181
|> SeqUtils.TakeRandom 1
178182
|> Seq.tryHead
179183

NOnion/Network/TorStream.fs

+35-8
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ type private StreamControlMessage =
2828
offset: int *
2929
length: int *
3030
replyChannel: AsyncReplyChannel<OperationResult<unit>>
31-
| StartServiceConnectionProcess of
32-
port: int *
31+
| StartStreamConnectionProcess of
32+
address: string *
3333
streamObj: ITorStream *
3434
replyChannel: AsyncReplyChannel<OperationResult<Task<uint16>>>
3535
| StartDirectoryConnectionProcess of
@@ -120,7 +120,10 @@ type TorStream(circuit: TorCircuit) =
120120
"Unexpected state when trying to send data over stream"
121121
}
122122

123-
let startServiceConnectionProcess (port: int) (streamObj: ITorStream) =
123+
let startStreamConnectionProcess
124+
(address: string)
125+
(streamObj: ITorStream)
126+
=
124127
async {
125128
let streamId = circuit.RegisterStream streamObj None
126129

@@ -139,7 +142,7 @@ type TorStream(circuit: TorCircuit) =
139142
streamId
140143
(RelayBegin
141144
{
142-
RelayBegin.Address = (sprintf ":%i" port)
145+
RelayBegin.Address = address
143146
Flags = 0u
144147
})
145148
None
@@ -236,9 +239,9 @@ type TorStream(circuit: TorCircuit) =
236239
do!
237240
safeSend data offset length
238241
|> TryExecuteAsyncAndReplyAsResult replyChannel
239-
| StartServiceConnectionProcess(port, streamObj, replyChannel) ->
242+
| StartStreamConnectionProcess(address, streamObj, replyChannel) ->
240243
do!
241-
startServiceConnectionProcess port streamObj
244+
startStreamConnectionProcess address streamObj
242245
|> TryExecuteAsyncAndReplyAsResult replyChannel
243246
| StartDirectoryConnectionProcess(streamObj, replyChannel) ->
244247
do!
@@ -463,8 +466,8 @@ type TorStream(circuit: TorCircuit) =
463466
let! completionTaskRes =
464467
streamControlMailBox.PostAndAsyncReply(
465468
(fun replyChannel ->
466-
StreamControlMessage.StartServiceConnectionProcess(
467-
port,
469+
StreamControlMessage.StartStreamConnectionProcess(
470+
sprintf ":%i" port,
468471
self,
469472
replyChannel
470473
)
@@ -502,6 +505,30 @@ type TorStream(circuit: TorCircuit) =
502505
member self.ConnectToDirectoryAsync() =
503506
self.ConnectToDirectory() |> Async.StartAsTask
504507

508+
member self.ConnectToOutside (address: string) (port: int) =
509+
async {
510+
let! completionTaskRes =
511+
streamControlMailBox.PostAndAsyncReply(
512+
(fun replyChannel ->
513+
StreamControlMessage.StartStreamConnectionProcess(
514+
sprintf "%s:%i" address port,
515+
self,
516+
replyChannel
517+
)
518+
),
519+
Constants.StreamCreationTimeout.TotalMilliseconds |> int
520+
)
521+
522+
return!
523+
completionTaskRes
524+
|> UnwrapResult
525+
|> Async.AwaitTask
526+
|> FSharpUtil.WithTimeout Constants.StreamCreationTimeout
527+
}
528+
529+
member self.ConnectToOutsideAsync(address, port) =
530+
self.ConnectToOutside address port |> Async.StartAsTask
531+
505532
member private self.RegisterIncomingStream(streamId: uint16) =
506533
async {
507534
let! registerationResult =

0 commit comments

Comments
 (0)