/** * internal function to use the tor-resolve-functionality * * @param query a hostname to be resolved, or for a reverse lookup: A.B.C.D.in-addr.arpa * @return either an InetAddress (normal query), or a String (reverse-DNS-lookup) */ private Object resolve_internal(String query) throws IOException { try { // check, if tor is still in startup-phase checkStartup(); // try to resolv query over all existing circuits // so iterate over all TLS-Connections Iterator<String> i = fnh.tls.keySet().iterator(); while (i.hasNext()) { TLSConnection tls = fnh.tls.get(i.next()); // and over all circuits in each TLS-Connection Iterator<Integer> i2 = tls.circuits.keySet().iterator(); while (i2.hasNext()) { Circuit circuit = (Circuit) tls.circuits.get(i2.next()); try { if (circuit.established) { // if an answer is given, we're satisfied ResolveStream rs = new ResolveStream(circuit); Object o = rs.resolve(query); rs.close(); return o; } ; } catch (Exception e) { // in case of error, do nothing, but retry with the next // circuit } } } // if no circuit could give an answer (possibly there was no // established circuit?) // build a new circuit and ask this one to resolve the query ResolveStream rs = new ResolveStream(new Circuit(this, fnh, dir, new TCPStreamProperties())); Object o = rs.resolve(query); rs.close(); return o; } catch (TorException e) { throw new IOException("Error in Tor: " + e.getMessage()); } catch (InterruptedException e) { throw new IOException("Error in Tor: " + e.getMessage()); } }
/** * makes a connection to a remote service * * @param sp hostname, port to connect to and other stuff * @return some socket-thing */ public TCPStream connect(TCPStreamProperties sp) throws IOException, TorResolveFailedException { // Tor.log.logGeneral(Logger.VERBOSE, "Tor: Trying to connect to " + sp.hostname); if (sp.hostname == null) throw new IOException("Tor: no hostname is provided"); // check, if tor is still in startup-phase checkStartup(); // check whether the address is hidden if (sp.hostname.endsWith(".onion")) return connectToHidden(sp); boolean resolveException = false; Circuit[] cs = fnh.provideSuitableCircuits(sp, false); if (TorConfig.veryAggressiveStreamBuilding) { for (int j = 0; j < cs.length; ++j) { // start N asynchronous stream building threads try { StreamThread[] streamThreads = new StreamThread[cs.length]; for (int i = 0; i < cs.length; ++i) streamThreads[i] = new StreamThread(cs[i], sp); // wait for the first stream to return int chosenStream = -1; int waitingCounter = TorConfig.queueTimeoutStreamBuildup * 1000 / 10; while ((chosenStream < 0) && (waitingCounter >= 0)) { boolean atLeastOneAlive = false; for (int i = 0; (i < cs.length) && (chosenStream < 0); ++i) if (!streamThreads[i].isAlive()) { if ((streamThreads[i].stream != null) && (streamThreads[i].stream.established)) { chosenStream = i; } } else { atLeastOneAlive = true; } if (!atLeastOneAlive) break; Common.sleep(10); --waitingCounter; } // return one and close others if (chosenStream >= 0) { TCPStream returnValue = streamThreads[chosenStream].stream; new ClosingThread(streamThreads, chosenStream); return returnValue; } } catch (Exception e) { Logger.logStream(Logger.WARNING, "Tor.connect(): " + e.getMessage()); return null; } } } else { // build serial N streams, stop if successful for (int i = 0; i < cs.length; ++i) { try { return new TCPStream(cs[i], sp); } catch (TorResolveFailedException e) { Logger.logStream(Logger.WARNING, "Tor.connect: Resolve failed:" + e.getMessage()); resolveException = true; } catch (TorNoAnswerException e) { Logger.logStream(Logger.WARNING, "Tor.connect: Timeout on circuit:" + e.getMessage()); } catch (TorException e) { Logger.logStream( Logger.WARNING, "Tor.connect: TorException trying to reuse existing circuit:" + e.getMessage()); } catch (IOException e) { Logger.logStream(Logger.WARNING, "Tor.connect: IOException " + e.getMessage()); } } } if (resolveException) throw new TorResolveFailedException(); throw new IOException( "Tor.connect: unable to connect to " + sp.hostname + ":" + sp.port + " after " + sp.connect_retries + " retries"); }