internal void Extend(OnionRouter next_onion_router) { Logger.Debug("circuit::extend() [or: {0}, state: extending]", next_onion_router.Name); this.State = CircuitState.extending; _extend_node = CreateCircuitNode(next_onion_router); byte[] onion_skin = _extend_node.CreateOnionSkin(); byte[] relay_payload_bytes = new byte[] { (byte)( 4 + // ip address 2 + // port onion_skin.Length + // hybrid encrypted data length Constants.HASH_LEN) }; // identity fingerprint MemoryStream relay_payload_stream = new MemoryStream(relay_payload_bytes); StreamWrapper relay_payload_buffer = new StreamWrapper(relay_payload_stream, Endianness.big_endian); relay_payload_buffer.Write(next_onion_router.IPAddress.GetAddressBytes().SwapEndianness()); relay_payload_buffer.Write(next_onion_router.ORPort); relay_payload_buffer.Write(onion_skin); relay_payload_buffer.Write(Base16.Decode(next_onion_router.IdentityFingerprint)); SendRelayCell(0, CellCommand.relay_extend, relay_payload_bytes, // clients MUST only send // EXTEND cells inside RELAY_EARLY cells CellCommand.relay_early, _extend_node); WaitForState(Circuit.CircuitState.ready); Logger.Debug("circuit::extend() [or: {0}, state: extended]", next_onion_router.Name); }
private int FetchHiddenServiceDescriptor(int responsible_directory_index = 0) { for (int i = responsible_directory_index; i < _responsible_directory_list.Count; i++) { OnionRouter responsible_directory = _responsible_directory_list[i]; // create new circuit and extend it with responsible directory. Circuit directory_circuit = _socket.CreateCircuit(); directory_circuit.Extend(responsible_directory); byte replica = (byte)((i >= 3) ? 0 : 1); // create the directory stream on the directory circuit. TorStream directory_stream = directory_circuit.CreateDirStream(); // request the hidden service descriptor. Logger.Info( "hidden_service::fetch_hidden_service_descriptor() [path: {0}]", ("/tor/rendezvous2/" + Base32.encode(GetDescriptorId(replica)))); string request = "GET /tor/rendezvous2/" + Base32.encode(GetDescriptorId(replica)) + " HTTP/1.1\r\nHost: " + responsible_directory.IPAddress.ToString() + "\r\n\r\n"; directory_stream.Write(ASCIIEncoding.ASCII.GetBytes(request), 0, request.Length); StreamReader stream_reader = new StreamReader(directory_stream); string hidden_service_descriptor = stream_reader.ReadToEnd(); // parse hidden service descriptor. if (!hidden_service_descriptor.Contains("404 Not found")) { HiddenServiceDescriptorParser parser = new HiddenServiceDescriptorParser(); parser.parse(_owner, hidden_service_descriptor); _introduction_point_list = parser.introduction_point_list; parser.introduction_point_list = null; return(i); } } return(-1); }
internal void Register(OnionRouter router) { if (null == router) { throw new ArgumentNullException(); } _onionRouterMap.Add(router.IdentityFingerprint, router); }
internal void Create(OnionRouter firstRouter) { Logger.Debug("circuit::create() [or: {0}, state: creating]", firstRouter.Name); this.State = CircuitState.creating; _extend_node = CreateCircuitNode(firstRouter); SendCell(new Cell(_circuit_id, CellCommand.create, _extend_node.CreateOnionSkin())); WaitForState(CircuitState.ready); Logger.Debug("circuit::create() [or: {0}, state: created]", firstRouter.Name); }
internal TorSocket(OnionRouter onion_router = null) { _onion_router = onion_router; _recv_cell_loop_thread = new Thread(ReceiveCellsLoop); if (null != onion_router) { Connect(onion_router); } }
internal void Connect(OnionRouter or) { _onion_router = or; _socket.Connect(_onion_router.IPAddress.ToString(), _onion_router.ORPort); State = SocketState.handshake_in_progress; // handshake. SendVersion(); ReceiveVersions(); ReceiveCertificates(); ReceiveNetworkInfo(); SendNetInfo(); // start the receive loop. _recv_cell_loop_thread.Start(); }
internal OnionRouter GetRandomRouter(SearchCriteria criteria = null) { List <OnionRouter> candidates = new List <OnionRouter>(); foreach (KeyValuePair <string, OnionRouter> pair in _onionRouterMap) { OnionRouter router = pair.Value; if (null != criteria) { if (!Helpers.IsNullOrEmpty(criteria.allowed_dir_ports)) { if (-1 == criteria.allowed_dir_ports.IndexOf(router.DirPort)) { continue; } } if (!Helpers.IsNullOrEmpty(criteria.allowed_or_ports)) { if (-1 == criteria.allowed_or_ports.IndexOf(router.ORPort)) { continue; } } if (!Helpers.IsNullOrEmpty(criteria.forbidden_onion_routers)) { if (-1 == criteria.forbidden_onion_routers.IndexOf(router)) { continue; } } if (criteria.flags != OnionRouter.StatusFlags.none) { if ((router.Flags & criteria.flags) != criteria.flags) { continue; } } } candidates.Add(router); } if (0 == candidates.Count) { return(null); } OnionRouter nextHop = candidates.GetRandom(); return(null); }
internal void RendezvousIntroduce(Circuit rendezvous_circuit, byte[] rendezvous_cookie) { Globals.Assert(rendezvous_cookie.Length == 20); OnionRouter introduction_point = FinalCircuitNode.OnionRouter; OnionRouter introducee = rendezvous_circuit.FinalCircuitNode.OnionRouter; Logger.Debug("circuit::rendezvous_introduce() [or: {0}, state: introducing]", introduction_point.Name); this.State = Circuit.CircuitState.rendezvous_introducing; Logger.Debug("circuit::rendezvous_introduce() [or: {0}, state: completing]", introduction_point.Name); rendezvous_circuit.State = CircuitState.rendezvous_completing; // payload of the RELAY_COMMAND_INTRODUCE1 // command: // // PK_ID Identifier for Bob's PK [20 octets] // VER Version byte: set to 2. [1 octet] // IP Rendezvous point's address [4 octets] // PORT Rendezvous point's OR port [2 octets] // ID Rendezvous point identity ID [20 octets] // KLEN Length of onion key [2 octets] // KEY Rendezvous point onion key [KLEN octets] // RC Rendezvous cookie [20 octets] // g^x Diffie-Hellman data, part 1 [128 octets] // // compute PK_ID, aka hash of the service key. byte[] service_key_hash = SHA1.Hash(introduction_point.ServiceKey); // create rest of the payload in separate buffer; // it will be encrypted. byte[] handshake_bytes = new byte[] { (byte)( 1 + // version 4 + // ip address 2 + // port Constants.HASH_LEN + // identity_fingerprint 2 + // onion key size introducee.OnionKey.Length + // onion key 20 + // rendezvous cookie 128) }; // DH MemoryStream handshake_stream = new MemoryStream(handshake_bytes); StreamWrapper handshake_buffer = new StreamWrapper(handshake_stream, Endianness.big_endian); rendezvous_circuit._extend_node = CreateCircuitNode(introduction_point, CircuitNode.Type.introduction_point); handshake_buffer.Write((byte)2); handshake_buffer.Write(introducee.IPAddress.GetAddressBytes().SwapEndianness()); handshake_buffer.Write(introducee.ORPort); handshake_buffer.Write(Base16.Decode(introducee.IdentityFingerprint)); handshake_buffer.Write((ushort)(introducee.OnionKey.Length)); handshake_buffer.Write(introducee.OnionKey); handshake_buffer.Write(rendezvous_cookie); handshake_buffer.Write(rendezvous_circuit._extend_node.KeyAgreement.PublicKey.ToBytes()); byte[] handshake_encrypted = HybridEncryptor.Encrypt(handshake_bytes, introduction_point.ServiceKey); // compose the final payload. List <byte> relay_payload_bytes = new List <byte>(); relay_payload_bytes.AddRange(service_key_hash); relay_payload_bytes.AddRange(handshake_encrypted); // send the cell. SendRelayCell(0, CellCommand.relay_command_introduce1, relay_payload_bytes.ToArray()); WaitForState(Circuit.CircuitState.rendezvous_introduced); Logger.Debug("circuit::rendezvous_introduce() [or: {0}, state: introduced]", introduction_point.Name); rendezvous_circuit.WaitForState(Circuit.CircuitState.rendezvous_completed); Logger.Debug("circuit::rendezvous_introduce() [or: {0}, state: completed]", introduction_point.Name); }
private CircuitNode CreateCircuitNode(OnionRouter or, CircuitNode.Type type = CircuitNode.Type.normal) { return(new CircuitNode(this, or, type)); }
internal Socket(OnionRouter first_hop) { _first_hop = first_hop; _protocol_version = 3; Connect(first_hop.IPAddress, first_hop.ORPort); }