commit 2db5c12fe9d8efa63a324f4b0680e3fd33715753 Author: Karsten Loesing karsten.loesing@gmx.net Date: Mon May 21 15:32:36 2012 +0200
Make some major changes to the bridge descriptor sanitizer.
- Bridge network statuses contain a "published" line containing the publication timestamp, so that parsers don't have to learn that timestamp from the file name anymore.
- Bridge network status entries are ordered by hex-encoded fingerprint, not by base64-encoded fingerprint, which is mostly a cosmetic change.
- Server descriptors and extra-info descriptors are stored under the SHA1 hashes of the descriptor identifiers of their non-scrubbed forms. Previously, descriptors were (supposed to be; see #5607) stored under the digests of their scrubbed forms. The reason for hashing digests is to prevent looking up an existing descriptor from the bridge authority by its non-scrubbed descriptor digest. With this change, we don't have to repair references between statuses, server descriptors, and extra-info descriptors anymore which turned out to be error-prone (#5608). Server descriptors and extra-info descriptors contain a new "router-digest" line with the hex-formatted descriptor identifier. These lines are necessary, because we cannot calculate the identifier anymore and because we don't want to rely on the file name.
- Stop sanitizing bridge nicknames (#5684).
- Stop sanitizing *-stats lines (#5807).
- All sanitized bridge descriptors contain @type annotations (#5651). --- .../ernie/db/BridgeDescriptorParser.java | 20 +- .../torproject/ernie/db/BridgeSnapshotReader.java | 4 +- .../ernie/db/SanitizedBridgesWriter.java | 908 ++++---------------- 3 files changed, 151 insertions(+), 781 deletions(-)
diff --git a/src/org/torproject/ernie/db/BridgeDescriptorParser.java b/src/org/torproject/ernie/db/BridgeDescriptorParser.java index 0be62f7..7773525 100644 --- a/src/org/torproject/ernie/db/BridgeDescriptorParser.java +++ b/src/org/torproject/ernie/db/BridgeDescriptorParser.java @@ -16,7 +16,7 @@ public class BridgeDescriptorParser { this.logger = Logger.getLogger(BridgeDescriptorParser.class.getName()); } - public void parse(byte[] allData, String dateTime, boolean sanitized) { + public void parse(byte[] allData, String dateTime) { try { BufferedReader br = new BufferedReader(new StringReader( new String(allData, "US-ASCII"))); @@ -25,27 +25,15 @@ public class BridgeDescriptorParser { return; } else if (line.startsWith("r ")) { if (this.sbw != null) { - if (sanitized) { - this.sbw.storeSanitizedNetworkStatus(allData, dateTime); - } else { - this.sbw.sanitizeAndStoreNetworkStatus(allData, dateTime); - } + this.sbw.sanitizeAndStoreNetworkStatus(allData, dateTime); } } else if (line.startsWith("router ")) { if (this.sbw != null) { - if (sanitized) { - this.sbw.storeSanitizedServerDescriptor(allData); - } else { - this.sbw.sanitizeAndStoreServerDescriptor(allData); - } + this.sbw.sanitizeAndStoreServerDescriptor(allData); } } else if (line.startsWith("extra-info ")) { if (this.sbw != null) { - if (sanitized) { - this.sbw.storeSanitizedExtraInfoDescriptor(allData); - } else { - this.sbw.sanitizeAndStoreExtraInfoDescriptor(allData); - } + this.sbw.sanitizeAndStoreExtraInfoDescriptor(allData); } } } catch (IOException e) { diff --git a/src/org/torproject/ernie/db/BridgeSnapshotReader.java b/src/org/torproject/ernie/db/BridgeSnapshotReader.java index 1683b58..0de9d83 100644 --- a/src/org/torproject/ernie/db/BridgeSnapshotReader.java +++ b/src/org/torproject/ernie/db/BridgeSnapshotReader.java @@ -119,7 +119,7 @@ public class BridgeSnapshotReader { } } if (firstLine.startsWith("r ")) { - bdp.parse(allData, dateTime, false); + bdp.parse(allData, dateTime); parsedStatuses++; } else if (descriptorImportHistory.contains(fileDigest)) { /* Skip server descriptors or extra-info descriptors if @@ -155,7 +155,7 @@ public class BridgeSnapshotReader { DigestUtils.sha(descBytes)); if (!descriptorImportHistory.contains( descriptorDigest)) { - bdp.parse(descBytes, dateTime, false); + bdp.parse(descBytes, dateTime); descriptorImportHistory.add(descriptorDigest); if (firstLine.startsWith("router ")) { parsedServerDescriptors++; diff --git a/src/org/torproject/ernie/db/SanitizedBridgesWriter.java b/src/org/torproject/ernie/db/SanitizedBridgesWriter.java index ff53cf0..ba33026 100644 --- a/src/org/torproject/ernie/db/SanitizedBridgesWriter.java +++ b/src/org/torproject/ernie/db/SanitizedBridgesWriter.java @@ -25,141 +25,15 @@ import org.apache.commons.codec.binary.*; * (lists of all bridges at a given time), server descriptors (published * by the bridge to advertise their capabilities), and extra-info * descriptors (published by the bridge, mainly for statistical analysis). - * - * Network statuses, server descriptors, and extra-info descriptors are - * linked via descriptor digests: extra-info descriptors are referenced - * from server descriptors, and server descriptors are referenced from - * network statuses. These references need to be changed during the - * sanitizing process, because descriptor contents change and so do the - * descriptor digests. - * - * No assumptions are made about the order in which bridge descriptors are - * parsed. The approach taken here is to sanitize bridge descriptors even - * with incomplete knowledge about references and to update them as soon - * as these information get known. We are keeping a persistent data - * structure, the bridge descriptor mapping, to hold information about - * every single descriptor. The idea is that every descriptor is (a) - * referenced from a network status and consists of (b) a server - * descriptor and (c) an extra-info descriptor, both of which are - * published at the same time. Using this data structure, we can repair - * references as soon as we learn more about the descriptor and regardless - * of the order of incoming bridge descriptors. - * - * The process of sanitizing a bridge descriptor is as follows, depending - * on the type of descriptor: - * - * Network statuses are processed by sanitizing every r line separately - * and looking up whether the descriptor mapping contains a bridge with - * given identity hash and descriptor publication time. If so, the new - * server descriptor identifier can be added. If not, we're adding all - * 0's. - * - * While sanitizing a server descriptor, its identity hash and publication - * time are looked up in order to put in the extra-info descriptor - * identifier in case the corresponding extra-info descriptor was - * sanitized before. Further, its publication time is noted down, so that - * all network statuses that might be referencing this server descriptor - * can be re-written at the end of the sanitizing procedure. - * - * Extra-info descriptors are processed by looking up their identity hash - * and publication time in the descriptor mapping. If the corresponding - * server descriptor was sanitized before, the server descriptor is - * re-written to include the new extra-info descriptor digest, and the - * publication time is noted down in order to re-write the network - * statuses possibly referencing this extra-info descriptor and its - * corresponding server descriptor at the end of the sanitizing process. - * - * After sanitizing all bridge descriptors, the network statuses that - * might be referencing server descriptors which have been (re-)written - * during this execution are re-written, too. This may be necessary in - * order to update previously broken references to server descriptors. */ public class SanitizedBridgesWriter {
/** - * Hex representation of null reference that is written to bridge - * descriptors if we don't have the real reference, yet. - */ - private static final String NULL_REFERENCE = - "0000000000000000000000000000000000000000"; - - /** - * Mapping between a descriptor as referenced from a network status to - * the digests of server descriptor and extra-info descriptor. - */ - private static class DescriptorMapping { - - /** - * Creates a new mapping from comma-separated values as read from the - * persistent mapping file. - */ - private DescriptorMapping(String commaSeparatedValues) { - String[] parts = commaSeparatedValues.split(","); - this.hashedBridgeIdentity = parts[0]; - this.published = parts[1]; - this.serverDescriptorIdentifier = parts[2]; - this.extraInfoDescriptorIdentifier = parts[3]; - } - - /** - * Creates a new mapping for a given identity hash and descriptor - * publication time that has all 0's as descriptor digests. - */ - private DescriptorMapping(String hashedBridgeIdentity, - String published) { - this.hashedBridgeIdentity = hashedBridgeIdentity; - this.published = published; - this.serverDescriptorIdentifier = NULL_REFERENCE; - this.extraInfoDescriptorIdentifier = NULL_REFERENCE; - } - private String hashedBridgeIdentity; - private String published; - private String serverDescriptorIdentifier; - private String extraInfoDescriptorIdentifier; - - /** - * Returns a string representation of this descriptor mapping that can - * be written to the persistent mapping file. - */ - public String toString() { - return this.hashedBridgeIdentity + "," + this.published + "," - + this.serverDescriptorIdentifier + "," - + this.extraInfoDescriptorIdentifier; - } - } - - /** - * File containing the mapping between network status entries, server - * descriptors, and extra-info descriptors. - */ - private File bridgeDescriptorMappingsFile; - - /** - * Mapping between status entries, server descriptors, and extra-info - * descriptors. This mapping is required to re-establish the references - * from status entries to server descriptors and from server descriptors - * to extra-info descriptors. The original references are broken when - * sanitizing, because descriptor contents change and so do the - * descriptor digests that are used for referencing. Map key contains - * hashed bridge identity and descriptor publication time, map value - * contains map key plus new server descriptor identifier and new - * extra-info descriptor identifier. - */ - private SortedMap<String, DescriptorMapping> bridgeDescriptorMappings; - - /** * Logger for this class. */ private Logger logger;
/** - * Publication times of server descriptors and extra-info descriptors - * parsed in the current execution. These times are used to determine - * which statuses need to be rewritten at the end of the execution. - */ - private SortedSet<String> descriptorPublicationTimes; - - /** * Output directory for writing sanitized bridge descriptors. */ private File sanitizedBridgesDirectory; @@ -170,21 +44,20 @@ public class SanitizedBridgesWriter {
private SortedMap<String, byte[]> secretsForHashingIPAddresses;
- private String bridgeDescriptorMappingsCutOffTimestamp; + private String bridgeSanitizingCutOffTimestamp;
- private boolean haveWarnedAboutLimitedMapping; + private boolean haveWarnedAboutInterval;
private File bridgeIpSecretsFile;
private SecureRandom secureRandom;
/** - * Initializes this class, including reading in the known descriptor - * mapping. + * Initializes this class. */ public SanitizedBridgesWriter(File sanitizedBridgesDirectory, File statsDirectory, boolean replaceIPAddressesWithHashes, - long limitBridgeDescriptorMappings) { + long limitBridgeSanitizingInterval) {
if (sanitizedBridgesDirectory == null || statsDirectory == null) { throw new IllegalArgumentException(); @@ -198,11 +71,6 @@ public class SanitizedBridgesWriter { this.logger = Logger.getLogger( SanitizedBridgesWriter.class.getName());
- /* Initialize data structure. */ - this.bridgeDescriptorMappings = new TreeMap<String, - DescriptorMapping>(); - this.descriptorPublicationTimes = new TreeSet<String>(); - /* Initialize secure random number generator if we need it. */ if (this.replaceIPAddressesWithHashes) { try { @@ -259,57 +127,17 @@ public class SanitizedBridgesWriter { } }
- /* If we're configured to keep descriptor mappings only for a limited - * time, define the cut-off day and time. */ - if (limitBridgeDescriptorMappings >= 0L) { + /* If we're configured to keep secrets only for a limited time, define + * the cut-off day and time. */ + if (limitBridgeSanitizingInterval >= 0L) { SimpleDateFormat formatter = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss"); formatter.setTimeZone(TimeZone.getTimeZone("UTC")); - this.bridgeDescriptorMappingsCutOffTimestamp = formatter.format( + this.bridgeSanitizingCutOffTimestamp = formatter.format( System.currentTimeMillis() - 24L * 60L * 60L * 1000L - * limitBridgeDescriptorMappings); + * limitBridgeSanitizingInterval); } else { - this.bridgeDescriptorMappingsCutOffTimestamp = - "1999-12-31 23:59:59"; - } - - /* Read known descriptor mappings from disk. */ - this.bridgeDescriptorMappingsFile = new File( - "stats/bridge-descriptor-mappings"); - if (this.bridgeDescriptorMappingsFile.exists()) { - try { - BufferedReader br = new BufferedReader(new FileReader( - this.bridgeDescriptorMappingsFile)); - String line = null; - int read = 0, skipped = 0; - while ((line = br.readLine()) != null) { - if (line.split(",").length == 4) { - String[] parts = line.split(","); - if (this.bridgeDescriptorMappingsCutOffTimestamp. - compareTo(parts[1]) > 0) { - skipped++; - continue; - } - read++; - DescriptorMapping dm = new DescriptorMapping(line); - this.bridgeDescriptorMappings.put(parts[0] + "," + parts[1], - dm); - } else { - this.logger.warning("Corrupt line '" + line + "' in " - + this.bridgeDescriptorMappingsFile.getAbsolutePath() - + ". Skipping."); - continue; - } - } - br.close(); - this.logger.fine("Finished reading " + read + " descriptor " - + "mappings from disk, skipped " + skipped + "."); - } catch (IOException e) { - this.logger.log(Level.WARNING, "Could not read in " - + this.bridgeDescriptorMappingsFile.getAbsolutePath() - + "."); - return; - } + this.bridgeSanitizingCutOffTimestamp = "1999-12-31 23:59:59"; } }
@@ -446,10 +274,10 @@ public class SanitizedBridgesWriter { secret, 0, 31); } if (month.compareTo( - this.bridgeDescriptorMappingsCutOffTimestamp) < 0) { + this.bridgeSanitizingCutOffTimestamp) < 0) { this.logger.warning("Generated a secret that we won't make " - + "persistent, because it's outside our bridge descriptors " - + "mapping interval."); + + "persistent, because it's outside our bridge descriptor " + + "sanitizing interval."); } else { /* Append secret to file on disk immediately before using it, or * we might end with inconsistently sanitized bridges. */ @@ -476,9 +304,8 @@ public class SanitizedBridgesWriter { }
/** - * Sanitizes a network status and writes it to disk. Processes every r - * line separately and looks up whether the descriptor mapping contains - * a bridge with given identity hash and descriptor publication time. */ + * Sanitizes a network status and writes it to disk. + */ public void sanitizeAndStoreNetworkStatus(byte[] data, String publicationTime) {
@@ -488,13 +315,13 @@ public class SanitizedBridgesWriter { return; }
- if (this.bridgeDescriptorMappingsCutOffTimestamp. + if (this.bridgeSanitizingCutOffTimestamp. compareTo(publicationTime) > 0) { - this.logger.log(!this.haveWarnedAboutLimitedMapping ? Level.WARNING + this.logger.log(!this.haveWarnedAboutInterval ? Level.WARNING : Level.FINE, "Sanitizing and storing network status with " - + "publication time outside our descriptor mapping interval. " - + "We might not be able to repair references."); - this.haveWarnedAboutLimitedMapping = true; + + "publication time outside our descriptor sanitizing " + + "interval."); + this.haveWarnedAboutInterval = true; }
/* Parse the given network status line by line. */ @@ -508,64 +335,55 @@ public class SanitizedBridgesWriter { String mostRecentDescPublished = null; byte[] fingerprintBytes = null; String descPublicationTime = null; + String hashedBridgeIdentityHex = null; while ((line = br.readLine()) != null) {
/* r lines contain sensitive information that needs to be removed * or replaced. */ if (line.startsWith("r ")) {
+ /* Clear buffer from previously scrubbed lines. */ + if (scrubbed.length() > 0) { + String scrubbedLine = scrubbed.toString(); + scrubbedLines.put(hashedBridgeIdentityHex, scrubbedLine); + scrubbed = new StringBuilder(); + } + /* Parse the relevant parts of this r line. */ String[] parts = line.split(" "); + String nickname = parts[1]; fingerprintBytes = Base64.decodeBase64(parts[2] + "=="); + String descriptorIdentifier = parts[3]; descPublicationTime = parts[4] + " " + parts[5]; String address = parts[6]; String orPort = parts[7]; String dirPort = parts[8];
- /* Look up the descriptor in the descriptor mapping, or add a - * new mapping entry if there is none. */ - String hashedBridgeIdentityHex = Hex.encodeHexString( - DigestUtils.sha(fingerprintBytes)).toLowerCase(); - String mappingKey = hashedBridgeIdentityHex + "," - + descPublicationTime; - DescriptorMapping mapping = null; - if (this.bridgeDescriptorMappings.containsKey(mappingKey)) { - mapping = this.bridgeDescriptorMappings.get(mappingKey); - } else { - mapping = new DescriptorMapping(hashedBridgeIdentityHex. - toLowerCase(), descPublicationTime); - this.bridgeDescriptorMappings.put(mappingKey, mapping); - } - /* Determine most recent descriptor publication time. */ if (descPublicationTime.compareTo(publicationTime) <= 0 && (mostRecentDescPublished == null || - descPublicationTime.compareTo(mostRecentDescPublished) > 0)) { + descPublicationTime.compareTo( + mostRecentDescPublished) > 0)) { mostRecentDescPublished = descPublicationTime; }
/* Write scrubbed r line to buffer. */ + byte[] hashedBridgeIdentity = DigestUtils.sha(fingerprintBytes); String hashedBridgeIdentityBase64 = Base64.encodeBase64String( - DigestUtils.sha(fingerprintBytes)).substring(0, 27); - String sdi = Base64.encodeBase64String(Hex.decodeHex( - mapping.serverDescriptorIdentifier.toCharArray())). - substring(0, 27); - String scrubbedAddress = null; - try { - scrubbedAddress = scrubIpv4Address(address, fingerprintBytes, - descPublicationTime); - } catch (IOException e) { - return; - } - if (scrubbed.length() > 0) { - String scrubbedLine = scrubbed.toString(); - scrubbedLines.put(scrubbedLine.split(" ")[2], scrubbedLine); - scrubbed = new StringBuilder(); - } - scrubbed.append("r Unnamed " - + hashedBridgeIdentityBase64 + " " + sdi + " " - + descPublicationTime + " " + scrubbedAddress + " " - + orPort + " " + dirPort + "\n"); + hashedBridgeIdentity).substring(0, 27); + hashedBridgeIdentityHex = Hex.encodeHexString( + hashedBridgeIdentity); + String hashedDescriptorIdentifier = Base64.encodeBase64String( + DigestUtils.sha(Base64.decodeBase64(descriptorIdentifier + + "=="))).substring(0, 27); + String scrubbedAddress = scrubIpv4Address(address, + fingerprintBytes, + descPublicationTime); + scrubbed.append("r " + nickname + " " + + hashedBridgeIdentityBase64 + " " + + hashedDescriptorIdentifier + " " + descPublicationTime + + " " + scrubbedAddress + " " + orPort + " " + dirPort + + "\n");
/* Sanitize any addresses in a lines using the fingerprint and * descriptor publication time from the previous r line. */ @@ -598,7 +416,7 @@ public class SanitizedBridgesWriter { br.close(); if (scrubbed.length() > 0) { String scrubbedLine = scrubbed.toString(); - scrubbedLines.put(scrubbedLine.split(" ")[2], scrubbedLine); + scrubbedLines.put(hashedBridgeIdentityHex, scrubbedLine); scrubbed = new StringBuilder(); }
@@ -619,11 +437,8 @@ public class SanitizedBridgesWriter { } catch (ParseException e) { this.logger.log(Level.WARNING, "Could not parse timestamp in " + "bridge network status.", e); - } catch (IOException e) { - this.logger.log(Level.WARNING, "Could not parse bridge network " - + "status.", e); return; - } catch (DecoderException e) { + } catch (IOException e) { this.logger.log(Level.WARNING, "Could not parse bridge network " + "status.", e); return; @@ -650,6 +465,8 @@ public class SanitizedBridgesWriter {
/* Write sanitized network status to disk. */ BufferedWriter bw = new BufferedWriter(new FileWriter(statusFile)); + bw.write("@type bridge-network-status 1.0\n"); + bw.write("published " + publicationTime + "\n"); for (String scrubbed : scrubbedLines.values()) { bw.write(scrubbed); } @@ -663,12 +480,7 @@ public class SanitizedBridgesWriter { }
/** - * Sanitizes a bridge server descriptor and writes it to disk. Looks up - * up bridge identity hash and publication time in the descriptor - * mapping. After sanitizing a server descriptor, its publication time - * is noted down, so that all network statuses that might be referencing - * this server descriptor can be re-written at the end of the sanitizing - * procedure. + * Sanitizes a bridge server descriptor and writes it to disk. */ public void sanitizeAndStoreServerDescriptor(byte[] data) {
@@ -678,35 +490,18 @@ public class SanitizedBridgesWriter { return; }
- /* Parse descriptor to generate a sanitized version and to look it up - * in the descriptor mapping. */ - String scrubbedDesc = null; - DescriptorMapping mapping = null; + /* Parse descriptor to generate a sanitized version. */ + String scrubbedDesc = null, published = null; try { BufferedReader br = new BufferedReader(new StringReader( new String(data, "US-ASCII"))); StringBuilder scrubbed = new StringBuilder(); String line = null, hashedBridgeIdentity = null, address = null, - published = null, routerLine = null, scrubbedAddress = null; + routerLine = null, scrubbedAddress = null; List<String> orAddresses = null, scrubbedOrAddresses = null; boolean skipCrypto = false; while ((line = br.readLine()) != null) {
- /* When we have parsed both published and fingerprint line, look - * up descriptor in the descriptor mapping or create a new one if - * there is none. */ - if (mapping == null && published != null && - hashedBridgeIdentity != null) { - String mappingKey = hashedBridgeIdentity + "," + published; - if (this.bridgeDescriptorMappings.containsKey(mappingKey)) { - mapping = this.bridgeDescriptorMappings.get(mappingKey); - } else { - mapping = new DescriptorMapping(hashedBridgeIdentity, - published); - this.bridgeDescriptorMappings.put(mappingKey, mapping); - } - } - /* Skip all crypto parts that might be used to derive the bridge's * identity fingerprint. */ if (skipCrypto && !line.startsWith("-----END ")) { @@ -727,21 +522,18 @@ public class SanitizedBridgesWriter { } orAddresses.add(line.substring("or-address ".length()));
- /* Parse the publication time and add it to the list of descriptor - * publication times to re-write network statuses at the end of - * the sanitizing procedure. */ + /* Parse the publication time to see if we're still inside the + * sanitizing interval. */ } else if (line.startsWith("published ")) { published = line.substring("published ".length()); - if (this.bridgeDescriptorMappingsCutOffTimestamp. + if (this.bridgeSanitizingCutOffTimestamp. compareTo(published) > 0) { - this.logger.log(!this.haveWarnedAboutLimitedMapping + this.logger.log(!this.haveWarnedAboutInterval ? Level.WARNING : Level.FINE, "Sanitizing and storing " + "server descriptor with publication time outside our " - + "descriptor mapping interval. We might not be able to " - + "repair references."); - this.haveWarnedAboutLimitedMapping = true; + + "descriptor sanitizing interval."); + this.haveWarnedAboutInterval = true; } - this.descriptorPublicationTimes.add(published); scrubbed.append(line + "\n");
/* Parse the fingerprint to determine the hashed bridge @@ -775,6 +567,7 @@ public class SanitizedBridgesWriter { } catch (IOException e) { /* There's a persistence problem, so we shouldn't scrub more * IP addresses in this execution. */ + this.persistenceProblemWithSecrets = true; return; } scrubbed.append((line.startsWith("opt ") ? "opt " : "") @@ -792,9 +585,9 @@ public class SanitizedBridgesWriter { * descriptor to disk below. */ } else if (line.startsWith("router-signature")) { String[] routerLineParts = routerLine.split(" "); - scrubbedDesc = "router Unnamed " + scrubbedAddress + " " - + routerLineParts[3] + " " + routerLineParts[4] + " " - + routerLineParts[5] + "\n"; + scrubbedDesc = "router " + routerLineParts[1] + " " + + scrubbedAddress + " " + routerLineParts[3] + " " + + routerLineParts[4] + " " + routerLineParts[5] + "\n"; if (scrubbedOrAddresses != null) { for (String scrubbedOrAddress : scrubbedOrAddresses) { scrubbedDesc = scrubbedDesc += "or-address " @@ -804,14 +597,18 @@ public class SanitizedBridgesWriter { scrubbedDesc += scrubbed.toString(); break;
- /* Replace extra-info digest with the one we know from our - * descriptor mapping (which might be all 0's if we didn't parse - * the extra-info descriptor before). */ + /* Replace extra-info digest with the hashed digest of the + * non-scrubbed descriptor. */ } else if (line.startsWith("opt extra-info-digest ") || line.startsWith("extra-info-digest ")) { + String extraInfoDescriptorIdentifier = line.substring( + line.indexOf("extra-info-digest ") + + "extra-info-digest ".length()); + String hashedExtraInfoDescriptorIdentifier = + DigestUtils.shaHex(Hex.decodeHex( + extraInfoDescriptorIdentifier.toCharArray())).toUpperCase(); scrubbed.append((line.startsWith("opt ") ? "opt " : "") - + "extra-info-digest " - + mapping.extraInfoDescriptorIdentifier.toUpperCase() + + "extra-info-digest " + hashedExtraInfoDescriptorIdentifier + "\n");
/* Possibly sanitize reject lines if they contain the bridge's own @@ -844,7 +641,7 @@ public class SanitizedBridgesWriter { scrubbed.append(line + "\n");
/* Replace node fingerprints in the family line with their hashes - * and nicknames with Unnamed. */ + * and leave nicknames unchanged. */ } else if (line.startsWith("family ")) { StringBuilder familyLine = new StringBuilder("family"); for (String s : line.substring(7).split(" ")) { @@ -852,7 +649,7 @@ public class SanitizedBridgesWriter { familyLine.append(" $" + DigestUtils.shaHex(Hex.decodeHex( s.substring(1).toCharArray())).toUpperCase()); } else { - familyLine.append(" Unnamed"); + familyLine.append(" " + s); } } scrubbed.append(familyLine.toString() + "\n"); @@ -888,27 +685,44 @@ public class SanitizedBridgesWriter { return; }
- /* Determine new descriptor digest and write it to descriptor - * mapping. */ - String scrubbedHash = DigestUtils.shaHex(scrubbedDesc); - mapping.serverDescriptorIdentifier = scrubbedHash; - /* Determine filename of sanitized server descriptor. */ - String dyear = mapping.published.substring(0, 4); - String dmonth = mapping.published.substring(5, 7); + String descriptorDigest = null; + try { + String ascii = new String(data, "US-ASCII"); + String startToken = "router "; + String sigToken = "\nrouter-signature\n"; + int start = ascii.indexOf(startToken); + int sig = ascii.indexOf(sigToken) + sigToken.length(); + if (start >= 0 && sig >= 0 && sig > start) { + byte[] forDigest = new byte[sig - start]; + System.arraycopy(data, start, forDigest, 0, sig - start); + descriptorDigest = DigestUtils.shaHex(DigestUtils.sha(forDigest)); + } + } catch (UnsupportedEncodingException e) { + /* Handle below. */ + } + if (descriptorDigest == null) { + this.logger.log(Level.WARNING, "Could not calculate server " + + "descriptor digest."); + return; + } + String dyear = published.substring(0, 4); + String dmonth = published.substring(5, 7); File newFile = new File( this.sanitizedBridgesDirectory.getAbsolutePath() + "/" + dyear + "/" + dmonth + "/server-descriptors/" - + "/" + scrubbedHash.charAt(0) + "/" - + scrubbedHash.charAt(1) + "/" - + scrubbedHash); + + "/" + descriptorDigest.charAt(0) + "/" + + descriptorDigest.charAt(1) + "/" + + descriptorDigest);
/* Write sanitized server descriptor to disk, including all its parent * directories. */ try { newFile.getParentFile().mkdirs(); BufferedWriter bw = new BufferedWriter(new FileWriter(newFile)); + bw.write("@type bridge-server-descriptor 1.0\n"); bw.write(scrubbedDesc); + bw.write("router-digest " + descriptorDigest.toUpperCase() + "\n"); bw.close(); } catch (IOException e) { this.logger.log(Level.WARNING, "Could not write sanitized server " @@ -918,83 +732,33 @@ public class SanitizedBridgesWriter { }
/** - * Sanitizes an extra-info descriptor and writes it to disk. Looks up - * the bridge identity hash and publication time in the descriptor - * mapping. If the corresponding server descriptor was sanitized before, - * it is re-written to include the new extra-info descriptor digest and - * the publication time is noted down, too, so that all network statuses - * possibly referencing this extra-info descriptor and its corresponding - * server descriptor can be re-written at the end of the sanitizing - * procedure. + * Sanitizes an extra-info descriptor and writes it to disk. */ public void sanitizeAndStoreExtraInfoDescriptor(byte[] data) {
- /* Parse descriptor to generate a sanitized version and to look it up - * in the descriptor mapping. */ + /* Parse descriptor to generate a sanitized version. */ String scrubbedDesc = null, published = null; - DescriptorMapping mapping = null; try { BufferedReader br = new BufferedReader(new StringReader(new String( data, "US-ASCII"))); String line = null; StringBuilder scrubbed = null; String hashedBridgeIdentity = null; - boolean hasParsedBridgeStatsEndLine = false; while ((line = br.readLine()) != null) {
- /* When we have parsed both published and fingerprint line, look - * up descriptor in the descriptor mapping or create a new one if - * there is none. */ - if (mapping == null && published != null && - hashedBridgeIdentity != null) { - String mappingKey = hashedBridgeIdentity + "," + published; - if (this.bridgeDescriptorMappings.containsKey(mappingKey)) { - mapping = this.bridgeDescriptorMappings.get(mappingKey); - } else { - mapping = new DescriptorMapping(hashedBridgeIdentity, - published); - this.bridgeDescriptorMappings.put(mappingKey, mapping); - } - } - /* Parse bridge identity from extra-info line and replace it with * its hash in the sanitized descriptor. */ + String[] parts = line.split(" "); if (line.startsWith("extra-info ")) { hashedBridgeIdentity = DigestUtils.shaHex(Hex.decodeHex( - line.split(" ")[2].toCharArray())).toLowerCase(); - scrubbed = new StringBuilder("extra-info Unnamed " + parts[2].toCharArray())).toLowerCase(); + scrubbed = new StringBuilder("extra-info " + parts[1] + " " + hashedBridgeIdentity.toUpperCase() + "\n");
- /* Parse the publication time and add it to the list of descriptor - * publication times to re-write network statuses at the end of - * the sanitizing procedure. */ + /* Parse the publication time to determine the file name. */ } else if (line.startsWith("published ")) { scrubbed.append(line + "\n"); published = line.substring("published ".length()); - if (this.bridgeDescriptorMappingsCutOffTimestamp. - compareTo(published) > 0) { - this.logger.log(!this.haveWarnedAboutLimitedMapping - ? Level.WARNING : Level.FINE, "Sanitizing and storing " - + "extra-info descriptor with publication time outside " - + "our descriptor mapping interval. We might not be able " - + "to repair references."); - this.haveWarnedAboutLimitedMapping = true; - } - - /* Write bridge-stats lines unmodified to the sanitized - * descriptor and make sure that there's always a bridge-stats-end - * line preceding the bridge-ips line. */ - } else if (line.startsWith("bridge-stats-end ")) { - scrubbed.append(line + "\n"); - hasParsedBridgeStatsEndLine = true; - } else if (line.startsWith("bridge-ips ")) { - if (!hasParsedBridgeStatsEndLine) { - this.logger.fine("bridge-ips line without preceding " - + "bridge-stats-end line in bridge descriptor. " - + "Skipping."); - return; - } - scrubbed.append(line + "\n");
/* Write the following lines unmodified to the sanitized * descriptor. */ @@ -1003,7 +767,11 @@ public class SanitizedBridgesWriter { || line.startsWith("geoip-start-time ") || line.startsWith("geoip-client-origins ") || line.startsWith("geoip-db-digest ") - || line.startsWith("conn-bi-direct ")) { + || line.startsWith("conn-bi-direct ") + || line.startsWith("bridge-") + || line.startsWith("dirreq-") + || line.startsWith("cell-") + || line.startsWith("exit-")) { scrubbed.append(line + "\n");
/* When we reach the signature, we're done. Write the sanitized @@ -1011,11 +779,6 @@ public class SanitizedBridgesWriter { } else if (line.startsWith("router-signature")) { scrubbedDesc = scrubbed.toString(); break; - /* Don't include statistics that should only be contained in relay - * extra-info descriptors. */ - } else if (line.startsWith("dirreq-") || line.startsWith("cell-") - || line.startsWith("exit-")) { - continue;
/* If we encounter an unrecognized line, stop parsing and print * out a warning. We might have overlooked sensitive information @@ -1037,34 +800,44 @@ public class SanitizedBridgesWriter { return; }
- /* Determine new descriptor digest and check if write it to descriptor - * mapping. */ - String scrubbedDescHash = DigestUtils.shaHex(scrubbedDesc); - boolean extraInfoDescriptorIdentifierHasChanged = - !scrubbedDescHash.equals(mapping.extraInfoDescriptorIdentifier); - mapping.extraInfoDescriptorIdentifier = scrubbedDescHash; - if (extraInfoDescriptorIdentifierHasChanged && - !mapping.serverDescriptorIdentifier.equals(NULL_REFERENCE)) { - this.rewriteServerDescriptor(mapping); - this.descriptorPublicationTimes.add(published); + /* Determine filename of sanitized extra-info descriptor. */ + String descriptorDigest = null; + try { + String ascii = new String(data, "US-ASCII"); + String startToken = "extra-info "; + String sigToken = "\nrouter-signature\n"; + int start = ascii.indexOf(startToken); + int sig = ascii.indexOf(sigToken) + sigToken.length(); + if (start >= 0 && sig >= 0 && sig > start) { + byte[] forDigest = new byte[sig - start]; + System.arraycopy(data, start, forDigest, 0, sig - start); + descriptorDigest = DigestUtils.shaHex(DigestUtils.sha(forDigest)); + } + } catch (UnsupportedEncodingException e) { + /* Handle below. */ } - - /* Determine filename of sanitized server descriptor. */ - String dyear = mapping.published.substring(0, 4); - String dmonth = mapping.published.substring(5, 7); + if (descriptorDigest == null) { + this.logger.log(Level.WARNING, "Could not calculate extra-info " + + "descriptor digest."); + return; + } + String dyear = published.substring(0, 4); + String dmonth = published.substring(5, 7); File newFile = new File( this.sanitizedBridgesDirectory.getAbsolutePath() + "/" + dyear + "/" + dmonth + "/extra-infos/" - + scrubbedDescHash.charAt(0) + "/" - + scrubbedDescHash.charAt(1) + "/" - + scrubbedDescHash); + + descriptorDigest.charAt(0) + "/" + + descriptorDigest.charAt(1) + "/" + + descriptorDigest);
- /* Write sanitized server descriptor to disk, including all its parent - * directories. */ + /* Write sanitized extra-info descriptor to disk, including all its + * parent directories. */ try { newFile.getParentFile().mkdirs(); BufferedWriter bw = new BufferedWriter(new FileWriter(newFile)); + bw.write("@type bridge-extra-info 1.0\n"); bw.write(scrubbedDesc); + bw.write("router-digest " + descriptorDigest.toUpperCase() + "\n"); bw.close(); } catch (Exception e) { this.logger.log(Level.WARNING, "Could not write sanitized " @@ -1072,300 +845,6 @@ public class SanitizedBridgesWriter { } }
- public void storeSanitizedNetworkStatus(byte[] data, String published) { - if (this.bridgeDescriptorMappingsCutOffTimestamp. - compareTo(published) > 0) { - this.logger.log(!this.haveWarnedAboutLimitedMapping ? Level.WARNING - : Level.FINE, "Storing sanitized network status with " - + "publication time outside our descriptor mapping interval. " - + "We might not be able to repair references."); - this.haveWarnedAboutLimitedMapping = true; - } - String scrubbed = null; - try { - String ascii = new String(data, "US-ASCII"); - BufferedReader br2 = new BufferedReader(new StringReader(ascii)); - StringBuilder sb = new StringBuilder(); - String line = null; - while ((line = br2.readLine()) != null) { - if (line.startsWith("r ")) { - String hashedBridgeIdentity = Hex.encodeHexString( - Base64.decodeBase64(line.split(" ")[2] + "==")). - toLowerCase(); - String hashedBridgeIdentityBase64 = line.split(" ")[2]; - String readServerDescId = Hex.encodeHexString( - Base64.decodeBase64(line.split(" ")[3] + "==")). - toLowerCase(); - String descPublished = line.split(" ")[4] + " " - + line.split(" ")[5]; - String address = line.split(" ")[6]; - String mappingKey = (hashedBridgeIdentity + "," - + descPublished).toLowerCase(); - DescriptorMapping mapping = null; - if (this.bridgeDescriptorMappings.containsKey(mappingKey)) { - mapping = this.bridgeDescriptorMappings.get(mappingKey); - } else { - mapping = new DescriptorMapping(hashedBridgeIdentity. - toLowerCase(), descPublished); - mapping.serverDescriptorIdentifier = readServerDescId; - this.bridgeDescriptorMappings.put(mappingKey, mapping); - } - String sdi = Base64.encodeBase64String(Hex.decodeHex( - mapping.serverDescriptorIdentifier.toCharArray())). - substring(0, 27); - String orPort = line.split(" ")[7]; - String dirPort = line.split(" ")[8]; - sb.append("r Unnamed " - + hashedBridgeIdentityBase64 + " " + sdi + " " - + descPublished + " " + address + " " + orPort + " " - + dirPort + "\n"); - } else { - sb.append(line + "\n"); - } - } - scrubbed = sb.toString(); - br2.close(); - } catch (DecoderException e) { - this.logger.log(Level.WARNING, "Could not parse server descriptor " - + "identifier. This must be a bug.", e); - return; - } catch (IOException e) { - this.logger.log(Level.WARNING, "Could not parse previously " - + "sanitized network status.", e); - return; - } - - /* Check if we need to overwrite the status file on disk. */ - if (new String(data).equals(scrubbed)) { - this.logger.finer("The bridge network status published " + published - + " has not changed, so we're not attempting to rewrite it."); - return; - } - - try { - /* Determine file name. */ - String syear = published.substring(0, 4); - String smonth = published.substring(5, 7); - String sday = published.substring(8, 10); - String stime = published.substring(11, 13) - + published.substring(14, 16) - + published.substring(17, 19); - File statusFile = new File( - this.sanitizedBridgesDirectory.getAbsolutePath() + "/" + syear - + "/" + smonth + "/statuses/" + sday + "/" + syear + smonth - + sday + "-" + stime + "-" - + "4A0CCD2DDC7995083D73F5D667100C8A5831F16D"); - - /* Create all parent directories to write this network status. */ - statusFile.getParentFile().mkdirs(); - - /* Write sanitized network status to disk. */ - BufferedWriter bw = new BufferedWriter(new FileWriter(statusFile)); - bw.write(scrubbed); - bw.close(); - } catch (IOException e) { - this.logger.log(Level.WARNING, "Could not write previously " - + "sanitized network status.", e); - return; - } - } - - public void storeSanitizedServerDescriptor(byte[] data) { - try { - String ascii = new String(data, "US-ASCII"); - BufferedReader br2 = new BufferedReader(new StringReader(ascii)); - StringBuilder sb = new StringBuilder(); - String line2 = null, published = null; - String hashedBridgeIdentity = null; - DescriptorMapping mapping = null; - while ((line2 = br2.readLine()) != null) { - if (mapping == null && published != null && - hashedBridgeIdentity != null) { - String mappingKey = (hashedBridgeIdentity + "," + published). - toLowerCase(); - if (this.bridgeDescriptorMappings.containsKey(mappingKey)) { - mapping = this.bridgeDescriptorMappings.get(mappingKey); - } else { - mapping = new DescriptorMapping(hashedBridgeIdentity. - toLowerCase(), published); - this.bridgeDescriptorMappings.put(mappingKey, mapping); - } - } - if (line2.startsWith("router ")) { - sb.append("router Unnamed " + line2.split(" ")[2] + " " - + line2.split(" ")[3] + " " + line2.split(" ")[4] + " " - + line2.split(" ")[5] + "\n"); - } else if (line2.startsWith("published ")) { - published = line2.substring("published ".length()); - if (this.bridgeDescriptorMappingsCutOffTimestamp. - compareTo(published) > 0) { - this.logger.log(!this.haveWarnedAboutLimitedMapping - ? Level.WARNING : Level.FINE, "Storing sanitized " - + "server descriptor with publication time outside our " - + "descriptor mapping interval. We might not be able to " - + "repair references."); - this.haveWarnedAboutLimitedMapping = true; - } - sb.append(line2 + "\n"); - this.descriptorPublicationTimes.add(published); - } else if (line2.startsWith("opt fingerprint ") || - line2.startsWith("fingerprint ")) { - hashedBridgeIdentity = line2.substring( - line2.indexOf("fingerprint") + "fingerprint".length()). - replaceAll(" ", "").toLowerCase(); - sb.append(line2 + "\n"); - } else if (line2.startsWith("opt extra-info-digest ") || - line2.startsWith("extra-info-digest")) { - sb.append((line2.startsWith("opt ") ? "opt " : "") - + "extra-info-digest " - + mapping.extraInfoDescriptorIdentifier.toUpperCase() - + "\n"); - } else { - sb.append(line2 + "\n"); - } - } - br2.close(); - String scrubbedDesc = sb.toString(); - String scrubbedHash = DigestUtils.shaHex(scrubbedDesc); - - mapping.serverDescriptorIdentifier = scrubbedHash; - String dyear = published.substring(0, 4); - String dmonth = published.substring(5, 7); - File newFile = new File( - this.sanitizedBridgesDirectory.getAbsolutePath() + "/" - + dyear + "/" + dmonth + "/server-descriptors/" - + scrubbedHash.substring(0, 1) + "/" - + scrubbedHash.substring(1, 2) + "/" - + scrubbedHash); - this.logger.finer("Storing server descriptor " - + newFile.getAbsolutePath()); - newFile.getParentFile().mkdirs(); - BufferedWriter bw = new BufferedWriter(new FileWriter( - newFile)); - bw.write(scrubbedDesc); - bw.close(); - } catch (IOException e) { - this.logger.log(Level.WARNING, "Could not store unsanitized server " - + "descriptor.", e); - } - } - - public void storeSanitizedExtraInfoDescriptor(byte[] data) { - try { - String ascii = new String(data, "US-ASCII"); - BufferedReader br2 = new BufferedReader(new StringReader(ascii)); - StringBuilder sb = new StringBuilder(); - String line2 = null, published = null; - String hashedBridgeIdentity = null; - DescriptorMapping mapping = null; - while ((line2 = br2.readLine()) != null) { - if (mapping == null && published != null && - hashedBridgeIdentity != null) { - String mappingKey = (hashedBridgeIdentity + "," + published). - toLowerCase(); - if (this.bridgeDescriptorMappings.containsKey(mappingKey)) { - mapping = this.bridgeDescriptorMappings.get(mappingKey); - } else { - mapping = new DescriptorMapping(hashedBridgeIdentity. - toLowerCase(), published); - this.bridgeDescriptorMappings.put(mappingKey, mapping); - } - } - if (line2.startsWith("extra-info ")) { - hashedBridgeIdentity = line2.split(" ")[2]; - sb.append("extra-info Unnamed " + hashedBridgeIdentity - + "\n"); - } else if (line2.startsWith("published ")) { - sb.append(line2 + "\n"); - published = line2.substring("published ".length()); - if (this.bridgeDescriptorMappingsCutOffTimestamp. - compareTo(published) > 0) { - this.logger.log(!this.haveWarnedAboutLimitedMapping - ? Level.WARNING : Level.FINE, "Storing sanitized " - + "extra-info descriptor with publication time outside " - + "our descriptor mapping interval. We might not be able " - + "to repair references."); - this.haveWarnedAboutLimitedMapping = true; - } - this.descriptorPublicationTimes.add(published); - } else { - sb.append(line2 + "\n"); - } - } - br2.close(); - String scrubbedDesc = sb.toString(); - String scrubbedHash = DigestUtils.shaHex(scrubbedDesc); - mapping.extraInfoDescriptorIdentifier = scrubbedHash; - String dyear = published.substring(0, 4); - String dmonth = published.substring(5, 7); - File newFile = new File( - this.sanitizedBridgesDirectory.getAbsolutePath() + "/" - + dyear + "/" + dmonth + "/extra-infos/" - + scrubbedHash.substring(0, 1) + "/" - + scrubbedHash.substring(1, 2) + "/" - + scrubbedHash); - this.logger.finer("Storing extra-info descriptor " - + newFile.getAbsolutePath()); - newFile.getParentFile().mkdirs(); - BufferedWriter bw = new BufferedWriter(new FileWriter( - newFile)); - bw.write(scrubbedDesc); - bw.close(); - } catch (IOException e) { - this.logger.log(Level.WARNING, "Could not store sanitized " - + "extra-info descriptor.", e); - } - } - - private void rewriteNetworkStatus(File status, String published) { - try { - FileInputStream fis = new FileInputStream(status); - BufferedInputStream bis = new BufferedInputStream(fis); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - int len; - byte[] data2 = new byte[1024]; - while ((len = bis.read(data2, 0, 1024)) >= 0) { - baos.write(data2, 0, len); - } - fis.close(); - byte[] allData = baos.toByteArray(); - this.storeSanitizedNetworkStatus(allData, published); - } catch (IOException e) { - this.logger.log(Level.WARNING, "Could not rewrite network " - + "status.", e); - } - } - - private void rewriteServerDescriptor(DescriptorMapping mapping) { - try { - String dyear = mapping.published.substring(0, 4); - String dmonth = mapping.published.substring(5, 7); - File serverDescriptorFile = new File( - this.sanitizedBridgesDirectory.getAbsolutePath() + "/" - + dyear + "/" + dmonth + "/server-descriptors/" - + mapping.serverDescriptorIdentifier.substring(0, 1) + "/" - + mapping.serverDescriptorIdentifier.substring(1, 2) + "/" - + mapping.serverDescriptorIdentifier); - FileInputStream fis = new FileInputStream(serverDescriptorFile); - BufferedInputStream bis = new BufferedInputStream(fis); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - int len; - byte[] data2 = new byte[1024]; - while ((len = bis.read(data2, 0, 1024)) >= 0) { - baos.write(data2, 0, len); - } - fis.close(); - byte[] allData = baos.toByteArray(); - this.storeSanitizedServerDescriptor(allData); - serverDescriptorFile.delete(); - this.logger.finer("Deleting server descriptor " - + serverDescriptorFile.getAbsolutePath()); - } catch (IOException e) { - this.logger.log(Level.WARNING, "Could not rewrite server " - + "descriptor.", e); - } - } - /** * Rewrite all network statuses that might contain references to server * descriptors we added or updated in this execution. This applies to @@ -1374,107 +853,10 @@ public class SanitizedBridgesWriter { */ public void finishWriting() {
- /* Prepare parsing and formatting timestamps. */ - SimpleDateFormat dateTimeFormat = - new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - SimpleDateFormat statusFileFormat = - new SimpleDateFormat("yyyyMMdd-HHmmss"); - statusFileFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - - /* Iterate over publication timestamps of previously sanitized - * descriptors. For every publication timestamp, we want to re-write - * the network statuses that we published up to 24 hours after that - * descriptor. We keep the timestamp of the last re-written network - * status in order to make sure we re-writing any network status at - * most once. */ - this.logger.fine("Rewriting network statuses that might have " - + "changed."); - String lastDescriptorPublishedPlus24Hours = "1970-01-01 00:00:00"; - for (String published : this.descriptorPublicationTimes) { - if (published.compareTo(lastDescriptorPublishedPlus24Hours) <= 0) { - continue; - } - // find statuses 24 hours after published - SortedSet<File> statusesToRewrite = new TreeSet<File>(); - long publishedTime; - try { - publishedTime = dateTimeFormat.parse(published).getTime(); - } catch (ParseException e) { - this.logger.log(Level.WARNING, "Could not parse publication " - + "timestamp '" + published + "'. Skipping.", e); - continue; - } - String[] dayOne = dateFormat.format(publishedTime).split("-"); - - File publishedDayOne = new File( - this.sanitizedBridgesDirectory.getAbsolutePath() + "/" - + dayOne[0] + "/" + dayOne[1] + "/statuses/" + dayOne[2]); - if (publishedDayOne.exists()) { - statusesToRewrite.addAll(Arrays.asList(publishedDayOne. - listFiles())); - } - long plus24Hours = publishedTime + 24L * 60L * 60L * 1000L; - lastDescriptorPublishedPlus24Hours = dateFormat.format(plus24Hours); - String[] dayTwo = dateFormat.format(plus24Hours).split("-"); - File publishedDayTwo = new File( - this.sanitizedBridgesDirectory.getAbsolutePath() + "/" - + dayTwo[0] + "/" + dayTwo[1] + "/statuses/" + dayTwo[2]); - if (publishedDayTwo.exists()) { - statusesToRewrite.addAll(Arrays.asList(publishedDayTwo. - listFiles())); - } - for (File status : statusesToRewrite) { - String statusPublished = status.getName().substring(0, 15); - long statusTime; - try { - statusTime = statusFileFormat.parse(statusPublished).getTime(); - } catch (ParseException e) { - this.logger.log(Level.WARNING, "Could not parse network " - + "status publication timestamp '" + published - + "'. Skipping.", e); - continue; - } - if (statusTime < publishedTime || statusTime > plus24Hours) { - continue; - } - this.rewriteNetworkStatus(status, - dateTimeFormat.format(statusTime)); - } - } - this.logger.fine("Finished rewriting network statuses."); - - /* Write descriptor mappings to disk. */ - try { - this.logger.fine("Writing descriptor mappings to disk."); - BufferedWriter bw = new BufferedWriter(new FileWriter( - this.bridgeDescriptorMappingsFile)); - int wrote = 0, skipped = 0; - for (DescriptorMapping mapping : - this.bridgeDescriptorMappings.values()) { - String mappingString = mapping.toString(); - if (this.bridgeDescriptorMappingsCutOffTimestamp. - compareTo(mappingString.split(",")[1]) > 0) { - skipped++; - } else { - wrote++; - bw.write(mapping.toString() + "\n"); - } - } - bw.close(); - this.logger.fine("Finished writing " + wrote + " descriptor " - + "mappings to disk, skipped " + skipped + "."); - } catch (IOException e) { - this.logger.log(Level.WARNING, "Could not write descriptor " - + "mappings to disk.", e); - } - /* Delete secrets that we don't need anymore. */ if (!this.secretsForHashingIPAddresses.isEmpty() && this.secretsForHashingIPAddresses.firstKey().compareTo( - this.bridgeDescriptorMappingsCutOffTimestamp) < 0) { + this.bridgeSanitizingCutOffTimestamp) < 0) { try { int kept = 0, deleted = 0; BufferedWriter bw = new BufferedWriter(new FileWriter( @@ -1482,7 +864,7 @@ public class SanitizedBridgesWriter { for (Map.Entry<String, byte[]> e : this.secretsForHashingIPAddresses.entrySet()) { if (e.getKey().compareTo( - this.bridgeDescriptorMappingsCutOffTimestamp) < 0) { + this.bridgeSanitizingCutOffTimestamp) < 0) { deleted++; } else { bw.write(e.getKey() + "," + Hex.encodeHexString(e.getValue())