[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [metrics-web/master] Support searching for IPv6 OR addresses in ExoneraTor.
commit 2aef30a3356bb4a7673e79275c53d4668e493eb7
Author: Karsten Loesing <karsten.loesing@xxxxxxx>
Date: Tue Dec 11 14:19:52 2012 +0100
Support searching for IPv6 OR addresses in ExoneraTor.
---
db/exonerator.sql | 60 ++++--
.../ernie/cron/ExoneraTorDatabaseImporter.java | 104 +++++++---
.../torproject/ernie/web/ExoneraTorServlet.java | 210 +++++++++++++++-----
3 files changed, 280 insertions(+), 94 deletions(-)
diff --git a/db/exonerator.sql b/db/exonerator.sql
index b3c7c62..6851e91 100755
--- a/db/exonerator.sql
+++ b/db/exonerator.sql
@@ -31,7 +31,8 @@ CREATE TABLE consensus (
-- a relay as running at a certain point in time. Only relays with the
-- Running flag shall be inserted into this table. If a relay advertises
-- more than one IP address, there is a distinct entry for each address in
--- this table.
+-- this table. If a relay advertises more than one TCP port on the same
+-- IP address, there is only a single entry in this table.
CREATE TABLE statusentry (
-- The valid-after time of the consensus that contains this entry.
@@ -45,11 +46,17 @@ CREATE TABLE statusentry (
-- descriptor published by the relay.
descriptor CHARACTER(40) NOT NULL,
- -- The most significant 3 bytes of the relay's onion routing address in
- -- hex notation. This column contains the /24 network of the IPv4 or
- -- IPv6 address. The purpose is to quickly reduce query results which
- -- works surprisingly well.
- oraddress24 CHARACTER(6) NOT NULL,
+ -- The most significant 3 bytes of the relay's onion routing IPv4
+ -- address in lower-case hex notation, or null if the relay's onion
+ -- routing address in this status entry is IPv6. The purpose is to
+ -- quickly reduce query results for relays in the same /24 network.
+ oraddress24 CHARACTER(6),
+
+ -- The most significant 6 bytes of the relay's onion routing IPv6
+ -- address in lower-case hex notation, or null if the relay's onion
+ -- routing address in this status entry is IPv4. The purpose is to
+ -- quickly reduce query results for relays in the same /48 network.
+ oraddress48 CHARACTER(12),
-- The relay's onion routing address. Can be an IPv4 or an IPv6
-- address. If a relay advertises more than one address, there are
@@ -77,6 +84,12 @@ CREATE INDEX statusentry_oraddress_validafterdate
CREATE INDEX statusentry_oraddress24_validafterdate
ON statusentry (oraddress24, DATE(validafter));
+-- The index on the most significant 6 bytes of the relay's onion routing
+-- address and on the valid-after date is used to speed up queries for
+-- other relays in the same /48 network.
+CREATE INDEX statusentry_oraddress48_validafterdate
+ ON statusentry (oraddress48, DATE(validafter));
+
-- The exitlistentry table stores the results of the active testing,
-- DNS-based exit list for exit nodes. An entry in this table means that
-- a relay was scanned at a given time and found to be exiting to the
@@ -88,10 +101,11 @@ CREATE TABLE exitlistentry (
-- The 40-character lower-case hex string identifying the relay.
fingerprint CHARACTER(40) NOT NULL,
- -- The most significant 3 bytes of the relay's exit address in hex
- -- notation. This column contains the /24 network of the IPv4 or IPv6
- -- address. The purpose is to quickly reduce query results.
- exitaddress24 CHARACTER(6) NOT NULL,
+ -- The most significant 3 bytes of the relay's exit IPv4 address in
+ -- lower-case hex notation, or null if the relay's exit address in this
+ -- entry is IPv6. The purpose is to quickly reduce query results for
+ -- relays exiting from the same /24 network.
+ exitaddress24 CHARACTER(6),
-- The IP address that the relay uses for exiting to the Internet. If
-- the relay uses more than one IP address, there are multiple entries
@@ -163,6 +177,7 @@ CREATE OR REPLACE FUNCTION insert_statusentry (
insert_fingerprint CHARACTER(40),
insert_descriptor CHARACTER(40),
insert_oraddress24 CHARACTER(6),
+ insert_oraddress48 CHARACTER(12),
insert_oraddress TEXT,
insert_rawstatusentry BYTEA)
RETURNS INTEGER AS $$
@@ -176,10 +191,10 @@ CREATE OR REPLACE FUNCTION insert_statusentry (
AND oraddress = insert_oraddress::INET) = 0 THEN
-- Insert the status entry.
INSERT INTO statusentry (validafter, fingerprint, descriptor,
- oraddress24, oraddress, rawstatusentry)
+ oraddress24, oraddress48, oraddress, rawstatusentry)
VALUES (insert_validafter, insert_fingerprint,
- insert_descriptor, insert_oraddress24, insert_oraddress::INET,
- insert_rawstatusentry);
+ insert_descriptor, insert_oraddress24, insert_oraddress48,
+ insert_oraddress::INET, insert_rawstatusentry);
-- Return 1 for a successfully inserted status entry.
RETURN 1;
ELSE
@@ -305,9 +320,8 @@ CREATE OR REPLACE FUNCTION search_statusentries_by_address_date (
ORDER BY 3, 4, 6;
$$ LANGUAGE SQL;
--- Look up all IP adddresses in the /24 network of a given address to
--- suggest other addresses the user may be looking for.
--- TODO Revisit this function when enabling IPv6.
+-- Look up all IPv4 OR and exit addresses in the /24 network of a given
+-- address to suggest other addresses the user may be looking for.
CREATE OR REPLACE FUNCTION search_addresses_in_same_24 (
select_address24 CHARACTER(6),
select_date DATE)
@@ -326,3 +340,17 @@ CREATE OR REPLACE FUNCTION search_addresses_in_same_24 (
ORDER BY 1;
$$ LANGUAGE SQL;
+-- Look up all IPv6 OR addresses in the /48 network of a given address to
+-- suggest other addresses the user may be looking for.
+CREATE OR REPLACE FUNCTION search_addresses_in_same_48 (
+ select_address48 CHARACTER(12),
+ select_date DATE)
+ RETURNS TABLE(address TEXT) AS $$
+ SELECT HOST(oraddress)
+ FROM statusentry
+ WHERE oraddress48 = $1
+ AND DATE(validafter) >= $2 - 1
+ AND DATE(validafter) <= $2 + 1
+ ORDER BY 1;
+$$ LANGUAGE SQL;
+
diff --git a/src/org/torproject/ernie/cron/ExoneraTorDatabaseImporter.java b/src/org/torproject/ernie/cron/ExoneraTorDatabaseImporter.java
old mode 100755
new mode 100644
index c23b4eb..2e6916a
--- a/src/org/torproject/ernie/cron/ExoneraTorDatabaseImporter.java
+++ b/src/org/torproject/ernie/cron/ExoneraTorDatabaseImporter.java
@@ -18,6 +18,7 @@ import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Timestamp;
+import java.sql.Types;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
@@ -86,7 +87,7 @@ public class ExoneraTorDatabaseImporter {
insertDescriptorStatement = connection.prepareCall(
"{call insert_descriptor(?, ?)}");
insertStatusentryStatement = connection.prepareCall(
- "{call insert_statusentry(?, ?, ?, ?, ?, ?)}");
+ "{call insert_statusentry(?, ?, ?, ?, ?, ?, ?)}");
insertConsensusStatement = connection.prepareCall(
"{call insert_consensus(?, ?)}");
insertExitlistentryStatement = connection.prepareCall(
@@ -325,8 +326,8 @@ public class ExoneraTorDatabaseImporter {
try {
BufferedReader br = new BufferedReader(new StringReader(new String(
bytes, "US-ASCII")));
- String line, fingerprint = null, descriptor = null,
- orAddress24 = null, orAddress = null;
+ String line, fingerprint = null, descriptor = null;
+ Set<String> orAddresses = new HashSet<String>();
long validAfterMillis = -1L;
StringBuilder rawStatusentryBuilder = null;
boolean isRunning = false;
@@ -353,7 +354,8 @@ public class ExoneraTorDatabaseImporter {
byte[] rawStatusentry = rawStatusentryBuilder.toString().
getBytes();
importStatusentry(validAfterMillis, fingerprint, descriptor,
- orAddress24, orAddress, rawStatusentry);
+ orAddresses, rawStatusentry);
+ orAddresses = new HashSet<String>();
}
if (line.equals("directory-footer")) {
return;
@@ -369,26 +371,17 @@ public class ExoneraTorDatabaseImporter {
+ "=")).toLowerCase();
descriptor = Hex.encodeHexString(Base64.decodeBase64(parts[3]
+ "=")).toLowerCase();
- orAddress = parts[6];
- /* TODO Extend the following code for IPv6 once Tor supports
- * it. */
- String[] orAddressParts = orAddress.split("\\.");
- byte[] orAddress24Bytes = new byte[3];
- orAddress24Bytes[0] = (byte) Integer.parseInt(
- orAddressParts[0]);
- orAddress24Bytes[1] = (byte) Integer.parseInt(
- orAddressParts[1]);
- orAddress24Bytes[2] = (byte) Integer.parseInt(
- orAddressParts[2]);
- orAddress24 = Hex.encodeHexString(orAddress24Bytes);
+ orAddresses.add(parts[6]);
+ } else if (line.startsWith("a ")) {
+ rawStatusentryBuilder.append(line + "\n");
+ orAddresses.add(line.substring("a ".length(),
+ line.lastIndexOf(":")));
} else if (line.startsWith("s ") || line.equals("s")) {
rawStatusentryBuilder.append(line + "\n");
isRunning = line.contains(" Running");
} else if (rawStatusentryBuilder != null) {
rawStatusentryBuilder.append(line + "\n");
}
- /* TODO Extend this code to parse additional addresses once that's
- * implemented in Tor. */
}
} catch (IOException e) {
System.out.println("Could not parse consensus. Skipping.");
@@ -400,20 +393,71 @@ public class ExoneraTorDatabaseImporter {
private static Calendar calendarUTC = Calendar.getInstance(
TimeZone.getTimeZone("UTC"));
- /* Import a single status entry into the database. */
+ /* Import a status entry with one or more OR addresses into the
+ * database. */
private static void importStatusentry(long validAfterMillis,
- String fingerprint, String descriptor, String orAddress24,
- String orAddress, byte[] rawStatusentry) {
+ String fingerprint, String descriptor, Set<String> orAddresses,
+ byte[] rawStatusentry) {
try {
- insertStatusentryStatement.clearParameters();
- insertStatusentryStatement.setTimestamp(1,
- new Timestamp(validAfterMillis), calendarUTC);
- insertStatusentryStatement.setString(2, fingerprint);
- insertStatusentryStatement.setString(3, descriptor);
- insertStatusentryStatement.setString(4, orAddress24);
- insertStatusentryStatement.setString(5, orAddress);
- insertStatusentryStatement.setBytes(6, rawStatusentry);
- insertStatusentryStatement.execute();
+ for (String orAddress : orAddresses) {
+ insertStatusentryStatement.clearParameters();
+ insertStatusentryStatement.setTimestamp(1,
+ new Timestamp(validAfterMillis), calendarUTC);
+ insertStatusentryStatement.setString(2, fingerprint);
+ insertStatusentryStatement.setString(3, descriptor);
+ if (!orAddress.contains(":")) {
+ String[] addressParts = orAddress.split("\\.");
+ byte[] address24Bytes = new byte[3];
+ address24Bytes[0] = (byte) Integer.parseInt(addressParts[0]);
+ address24Bytes[1] = (byte) Integer.parseInt(addressParts[1]);
+ address24Bytes[2] = (byte) Integer.parseInt(addressParts[2]);
+ String orAddress24 = Hex.encodeHexString(address24Bytes);
+ insertStatusentryStatement.setString(4, orAddress24);
+ insertStatusentryStatement.setNull(5, Types.VARCHAR);
+ insertStatusentryStatement.setString(6, orAddress);
+ } else {
+ StringBuilder addressHex = new StringBuilder();
+ int start = orAddress.startsWith("[::") ? 2 : 1;
+ int end = orAddress.length()
+ - (orAddress.endsWith("::]") ? 2 : 1);
+ String[] parts = orAddress.substring(start, end).split(":", -1);
+ for (int i = 0; i < parts.length; i++) {
+ String part = parts[i];
+ if (part.length() == 0) {
+ addressHex.append("x");
+ } else if (part.length() <= 4) {
+ addressHex.append(String.format("%4s", part));
+ } else {
+ addressHex = null;
+ break;
+ }
+ }
+ String orAddress48 = null;
+ if (addressHex != null) {
+ String addressHexString = addressHex.toString();
+ addressHexString = addressHexString.replaceFirst("x",
+ String.format("%" + (33 - addressHexString.length())
+ + "s", "0"));
+ if (!addressHexString.contains("x") &&
+ addressHexString.length() == 32) {
+ orAddress48 = addressHexString.replaceAll(" ", "0").
+ toLowerCase().substring(0, 12);
+ }
+ }
+ if (orAddress48 != null) {
+ insertStatusentryStatement.setNull(4, Types.VARCHAR);
+ insertStatusentryStatement.setString(5, orAddress48);
+ insertStatusentryStatement.setString(6,
+ orAddress.replaceAll("[\\[\\]]", ""));
+ } else {
+ System.err.println("Could not import status entry with IPv6 "
+ + "address '" + orAddress + "'. Exiting.");
+ System.exit(1);
+ }
+ }
+ insertStatusentryStatement.setBytes(7, rawStatusentry);
+ insertStatusentryStatement.execute();
+ }
} catch (SQLException e) {
System.out.println("Could not import status entry. Exiting.");
System.exit(1);
diff --git a/src/org/torproject/ernie/web/ExoneraTorServlet.java b/src/org/torproject/ernie/web/ExoneraTorServlet.java
index d353c7b..687cf37 100644
--- a/src/org/torproject/ernie/web/ExoneraTorServlet.java
+++ b/src/org/torproject/ernie/web/ExoneraTorServlet.java
@@ -13,7 +13,9 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.text.ParseException;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
@@ -229,22 +231,59 @@ public class ExoneraTorServlet extends HttpServlet {
+ "on this IP address?</h3>");
/* Parse IP parameter. */
- /* TODO Extend the parsing code to accept IPv6 addresses, too. */
- Pattern ipAddressPattern = Pattern.compile(
+ Pattern ipv4AddressPattern = Pattern.compile(
"^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
"([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
"([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
"([01]?\\d\\d?|2[0-4]\\d|25[0-5])$");
+ Pattern ipv6AddressPattern = Pattern.compile(
+ "^\\[?[0-9a-fA-F:]{3,39}\\]?$");
String ipParameter = request.getParameter("ip");
String relayIP = "", ipWarning = "";
if (ipParameter != null && ipParameter.length() > 0) {
- Matcher ipParameterMatcher = ipAddressPattern.matcher(ipParameter);
- if (ipParameterMatcher.matches()) {
+ if (ipv4AddressPattern.matcher(ipParameter).matches()) {
String[] ipParts = ipParameter.split("\\.");
relayIP = Integer.parseInt(ipParts[0]) + "."
+ Integer.parseInt(ipParts[1]) + "."
+ Integer.parseInt(ipParts[2]) + "."
+ Integer.parseInt(ipParts[3]);
+ } else if (ipv6AddressPattern.matcher(ipParameter).matches()) {
+ if (ipParameter.startsWith("[") && ipParameter.endsWith("]")) {
+ ipParameter = ipParameter.substring(1,
+ ipParameter.length() - 1);
+ }
+ StringBuilder addressHex = new StringBuilder();
+ int start = ipParameter.startsWith("::") ? 1 : 0;
+ int end = ipParameter.length()
+ - (ipParameter.endsWith("::") ? 1 : 0);
+ String[] parts = ipParameter.substring(start, end).split(":", -1);
+ for (int i = 0; i < parts.length; i++) {
+ String part = parts[i];
+ if (part.length() == 0) {
+ addressHex.append("x");
+ } else if (part.length() <= 4) {
+ addressHex.append(String.format("%4s", part));
+ } else {
+ addressHex = null;
+ break;
+ }
+ }
+ if (addressHex != null) {
+ String addressHexString = addressHex.toString();
+ addressHexString = addressHexString.replaceFirst("x",
+ String.format("%" + (33 - addressHexString.length()) + "s",
+ "0"));
+ if (!addressHexString.contains("x") &&
+ addressHexString.length() == 32) {
+ relayIP = ipParameter.toLowerCase();
+ }
+ }
+ if (relayIP.length() < 1) {
+ ipWarning = "\"" + (ipParameter.length() > 40 ?
+ StringEscapeUtils.escapeHtml(ipParameter.substring(0, 40))
+ + "[...]" : StringEscapeUtils.escapeHtml(ipParameter))
+ + "\" is not a valid IP address.";
+ }
} else {
ipWarning = "\"" + (ipParameter.length() > 20 ?
StringEscapeUtils.escapeHtml(ipParameter.substring(0, 20))
@@ -309,7 +348,7 @@ public class ExoneraTorServlet extends HttpServlet {
String targetAddrWarning = "";
if (targetAddrParameter != null && targetAddrParameter.length() > 0) {
Matcher targetAddrParameterMatcher =
- ipAddressPattern.matcher(targetAddrParameter);
+ ipv4AddressPattern.matcher(targetAddrParameter);
if (targetAddrParameterMatcher.matches()) {
String[] targetAddrParts = targetAddrParameter.split("\\.");
targetIP = Integer.parseInt(targetAddrParts[0]) + "."
@@ -370,19 +409,21 @@ public class ExoneraTorServlet extends HttpServlet {
+ " <tr>\n"
+ " <td align=\"right\">IP address in question:"
+ "</td>\n"
- + " <td><input type=\"text\" name=\"ip\""
+ + " <td><input type=\"text\" name=\"ip\" size=\"30\""
+ (relayIP.length() > 0 ? " value=\"" + relayIP + "\""
: "")
+ ">"
+ (ipWarning.length() > 0 ? "<br><font color=\"red\">"
+ ipWarning + "</font>" : "")
+ "</td>\n"
- + " <td><i>(Ex.: 1.2.3.4)</i></td>\n"
+ + " <td><i>(Ex.: 86.59.21.38 or "
+ + "2001:858:2:2:aabb:0:563b:1526)</i></td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td align=\"right\">Date or timestamp, in "
+ "UTC:</td>\n"
+ " <td><input type=\"text\" name=\"timestamp\""
+ + " size=\"30\""
+ (timestampStr.length() > 0 ? " value=\"" + timestampStr + "\""
: "")
+ ">"
@@ -523,27 +564,35 @@ public class ExoneraTorServlet extends HttpServlet {
}
relevantDescriptors.get(descriptor).add(validafter);
String fingerprint = rs.getString(4);
- boolean orAddressMatches = rs.getString(5).equals(relayIP);
String exitaddress = rs.getString(6);
- String rLine = new String(rawstatusentry);
- rLine = rLine.substring(0, rLine.indexOf("\n"));
- String[] parts = rLine.split(" ");
- String htmlString = "r " + parts[1] + " " + parts[2] + " "
- + "<a href=\"serverdesc?desc-id=" + descriptor + "\" "
- + "target=\"_blank\">" + parts[3] + "</a> " + parts[4]
- + " " + parts[5] + " " + (orAddressMatches ? "<b>" : "")
- + parts[6] + (orAddressMatches ? "</b>" : "") + " " + parts[7]
- + " " + parts[8] + "\n";
+ StringBuilder html = new StringBuilder();
+ for (String line : new String(rawstatusentry).split("\n")) {
+ if (line.startsWith("r ")) {
+ String[] parts = line.split(" ");
+ boolean orAddressMatches = parts[6].equals(relayIP);
+ html.append("r " + parts[1] + " " + parts[2] + " "
+ + "<a href=\"serverdesc?desc-id=" + descriptor + "\" "
+ + "target=\"_blank\">" + parts[3] + "</a> " + parts[4]
+ + " " + parts[5] + " " + (orAddressMatches ? "<b>" : "")
+ + parts[6] + (orAddressMatches ? "</b>" : "") + " "
+ + parts[7] + " " + parts[8] + "\n");
+ } else if (line.startsWith("a ") &&
+ line.toLowerCase().contains(relayIP)) {
+ String address = line.substring("a ".length(),
+ line.lastIndexOf(":"));
+ String port = line.substring(line.lastIndexOf(":"));
+ html.append("a <b>" + address + "</b>" + port + "\n");
+ }
+ }
if (exitaddress != null && exitaddress.length() > 0) {
long scanned = rs.getTimestamp(7).getTime();
- htmlString += " [ExitAddress <b>" + exitaddress
- + "</b> " + validAfterTimeFormat.format(scanned)
- + "]\n";
+ html.append(" [ExitAddress <b>" + exitaddress
+ + "</b> " + validAfterTimeFormat.format(scanned) + "]\n");
}
if (!statusEntries.containsKey(validafter)) {
statusEntries.put(validafter, new TreeMap<String, String>());
}
- statusEntries.get(validafter).put(fingerprint, htmlString);
+ statusEntries.get(validafter).put(fingerprint, html.toString());
}
rs.close();
cs.close();
@@ -584,35 +633,93 @@ public class ExoneraTorServlet extends HttpServlet {
dateFormat.format(timestampTooOld),
dateFormat.format(timestampTooNew));
/* Run another query to find out if there are relays running on
- * other IP addresses in the same /24 network and tell the user
- * about it. */
- SortedSet<String> addressesInSameNetwork = new TreeSet<String>();
- String[] relayIPParts = relayIP.split("\\.");
- byte[] address24Bytes = new byte[3];
- address24Bytes[0] = (byte) Integer.parseInt(relayIPParts[0]);
- address24Bytes[1] = (byte) Integer.parseInt(relayIPParts[1]);
- address24Bytes[2] = (byte) Integer.parseInt(relayIPParts[2]);
- String address24 = Hex.encodeHexString(address24Bytes);
- try {
- CallableStatement cs = conn.prepareCall(
- "{call search_addresses_in_same_24 (?, ?)}");
- cs.setString(1, address24);
- cs.setDate(2, new java.sql.Date(timestamp));
- ResultSet rs = cs.executeQuery();
- while (rs.next()) {
- String address = rs.getString(1);
- addressesInSameNetwork.add(address);
+ * other IP addresses in the same /24 or /48 network and tell the
+ * user about it. */
+ List<String> addressesInSameNetwork = new ArrayList<String>();
+ if (!relayIP.contains(":")) {
+ String[] relayIPParts = relayIP.split("\\.");
+ byte[] address24Bytes = new byte[3];
+ address24Bytes[0] = (byte) Integer.parseInt(relayIPParts[0]);
+ address24Bytes[1] = (byte) Integer.parseInt(relayIPParts[1]);
+ address24Bytes[2] = (byte) Integer.parseInt(relayIPParts[2]);
+ String address24 = Hex.encodeHexString(address24Bytes);
+ try {
+ CallableStatement cs = conn.prepareCall(
+ "{call search_addresses_in_same_24 (?, ?)}");
+ cs.setString(1, address24);
+ cs.setDate(2, new java.sql.Date(timestamp));
+ ResultSet rs = cs.executeQuery();
+ while (rs.next()) {
+ String address = rs.getString(1);
+ if (!addressesInSameNetwork.contains(address)) {
+ addressesInSameNetwork.add(address);
+ }
+ }
+ rs.close();
+ cs.close();
+ } catch (SQLException e) {
+ /* No other addresses in the same /24 found. */
+ }
+ } else {
+ StringBuilder addressHex = new StringBuilder();
+ int start = relayIP.startsWith("::") ? 1 : 0;
+ int end = relayIP.length() - (relayIP.endsWith("::") ? 1 : 0);
+ String[] parts = relayIP.substring(start, end).split(":", -1);
+ for (int i = 0; i < parts.length; i++) {
+ String part = parts[i];
+ if (part.length() == 0) {
+ addressHex.append("x");
+ } else if (part.length() <= 4) {
+ addressHex.append(String.format("%4s", part));
+ } else {
+ addressHex = null;
+ break;
+ }
+ }
+ String address48 = null;
+ if (addressHex != null) {
+ String addressHexString = addressHex.toString();
+ addressHexString = addressHexString.replaceFirst("x",
+ String.format("%" + (33 - addressHexString.length())
+ + "s", "0"));
+ if (!addressHexString.contains("x") &&
+ addressHexString.length() == 32) {
+ address48 = addressHexString.replaceAll(" ", "0").
+ toLowerCase().substring(0, 12);
+ }
+ }
+ if (address48 != null) {
+ try {
+ CallableStatement cs = conn.prepareCall(
+ "{call search_addresses_in_same_48 (?, ?)}");
+ cs.setString(1, address48);
+ cs.setDate(2, new java.sql.Date(timestamp));
+ ResultSet rs = cs.executeQuery();
+ while (rs.next()) {
+ String address = rs.getString(1);
+ if (!addressesInSameNetwork.contains(address)) {
+ addressesInSameNetwork.add(address);
+ }
+ }
+ rs.close();
+ cs.close();
+ } catch (SQLException e) {
+ /* No other addresses in the same /48 found. */
+ }
}
- rs.close();
- cs.close();
- } catch (SQLException e) {
- /* No other addresses in the same /24 found. */
}
if (!addressesInSameNetwork.isEmpty()) {
- out.print(" <p>The following other IP addresses of Tor "
- + "relays in the same /24 network were found in relay and/or "
- + "exit lists around the time that could be related to IP "
- + "address " + relayIP + ":</p>\n");
+ if (!relayIP.contains(":")) {
+ out.print(" <p>The following other IP addresses of Tor "
+ + "relays in the same /24 network were found in relay "
+ + "and/or exit lists around the time that could be related "
+ + "to IP address " + relayIP + ":</p>\n");
+ } else {
+ out.print(" <p>The following other IP addresses of Tor "
+ + "relays in the same /48 network were found in relay "
+ + "lists around the time that could be related to IP "
+ + "address " + relayIP + ":</p>\n");
+ }
out.print(" <ul>\n");
for (String s : addressesInSameNetwork) {
out.print(" <li>" + s + "</li>\n");
@@ -670,7 +777,8 @@ public class ExoneraTorServlet extends HttpServlet {
if (timestampIsDate) {
out.print("a relay list published on " + timestampStr);
} else {
- out.print("the most recent relay list preceding " + timestampStr);
+ out.print("the most recent relay list preceding "
+ + timestampStr);
}
out.print(". A possible reason for the relay being missing in a "
+ "relay list might be that some of the directory "
@@ -720,6 +828,12 @@ public class ExoneraTorServlet extends HttpServlet {
}
}
+ /* Looking up targets for IPv6 is not supported yet. */
+ if (relayIP.contains(":")) {
+ writeFooter(out);
+ return;
+ }
+
/* Second part: target */
out.println("<br><a name=\"exit\"></a><h3>Was this relay configured "
+ "to permit exiting to a given target?</h3>");
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits