commit ee7c3eb73824a84e33b6c44b60fa8a32f37ab71e Author: Karsten Loesing karsten.loesing@gmx.net Date: Tue Dec 8 10:40:19 2020 +0100
Parse version 3 onion service statistics lines.
Implements the library part of tpo/metrics/statistics#40002. --- CHANGELOG.md | 6 +- .../torproject/descriptor/ExtraInfoDescriptor.java | 55 +++++++++++++ .../descriptor/impl/ExtraInfoDescriptorImpl.java | 93 ++++++++++++++++++++++ .../java/org/torproject/descriptor/impl/Key.java | 3 + .../impl/ExtraInfoDescriptorImplTest.java | 46 +++++++++++ 5 files changed, 202 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md index c6886e8..8ff5723 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ -# Changes in version 2.??.? - 2020-??-?? +# Changes in version 2.15.0 - 2020-??-?? + + * Medium changes + - Parse version 3 onion service statistics contained in extra-info + descriptors.
# Changes in version 2.14.0 - 2020-08-07 diff --git a/src/main/java/org/torproject/descriptor/ExtraInfoDescriptor.java b/src/main/java/org/torproject/descriptor/ExtraInfoDescriptor.java index e094fed..b553a22 100644 --- a/src/main/java/org/torproject/descriptor/ExtraInfoDescriptor.java +++ b/src/main/java/org/torproject/descriptor/ExtraInfoDescriptor.java @@ -674,6 +674,61 @@ public interface ExtraInfoDescriptor extends Descriptor { */ Map<String, Double> getHidservDirOnionsSeenParameters();
+ /** + * Return the time in milliseconds since the epoch when the included version 3 + * onion service statistics interval ended, or -1 if no such statistics are + * included. + * + * @since 2.15.0 + */ + long getHidservV3StatsEndMillis(); + + /** + * Return the interval length of the included version 3 onion service + * statistics in seconds, or -1 if no such statistics are included. + * + * @since 2.15.0 + */ + long getHidservV3StatsIntervalLength(); + + /** + * Return the approximate number of RELAY cells seen in either direction on a + * version 3 onion service circuit after receiving and successfully processing + * a RENDEZVOUS1 cell, or null if no such statistics are included. + * + * @since 2.15.0 + */ + Double getHidservRendV3RelayedCells(); + + /** + * Return the obfuscation parameters applied to the original measurement value + * of RELAY cells seen in either direction on a version 3 onion service + * circuit after receiving and successfully processing a RENDEZVOUS1 cell, or + * null if no such statistics are included. + * + * @since 2.15.0 + */ + Map<String, Double> getHidservRendV3RelayedCellsParameters(); + + /** + * Return the approximate number of unique version 3 onion service identities + * seen in descriptors published to and accepted by this onion service + * directory, or null if no such statistics are included. + * + * @since 2.15.0 + */ + Double getHidservDirV3OnionsSeen(); + + /** + * Return the obfuscation parameters applied to the original measurement value + * of unique version 3 onion service identities seen in descriptors published + * to and accepted by this onion service directory, or null if no such + * statistics are included. + * + * @since 2.15.0 + */ + Map<String, Double> getHidservDirV3OnionsSeenParameters(); + /** * Return the time in milliseconds since the epoch when the included * padding-counts statistics ended, or -1 if no such statistics are included. diff --git a/src/main/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java b/src/main/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java index 5cab6ab..4f87237 100644 --- a/src/main/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java +++ b/src/main/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java @@ -225,6 +225,15 @@ public abstract class ExtraInfoDescriptorImpl extends DescriptorImpl case HIDSERV_DIR_ONIONS_SEEN: this.parseHidservDirOnionsSeenLine(line, partsNoOpt); break; + case HIDSERV_V3_STATS_END: + this.parseHidservV3StatsEndLine(line, partsNoOpt); + break; + case HIDSERV_REND_V3_RELAYED_CELLS: + this.parseHidservRendV3RelayedCellsLine(line, partsNoOpt); + break; + case HIDSERV_DIR_V3_ONIONS_SEEN: + this.parseHidservDirV3OnionsSeenLine(line, partsNoOpt); + break; case PADDING_COUNTS: this.parsePaddingCountsLine(line, partsNoOpt); break; @@ -764,6 +773,46 @@ public abstract class ExtraInfoDescriptorImpl extends DescriptorImpl partsNoOpt, 2); }
+ private void parseHidservV3StatsEndLine(String line, + String[] partsNoOpt) throws DescriptorParseException { + long[] parsedStatsEndData = this.parseStatsEndLine(line, partsNoOpt, + 5); + this.hidservV3StatsEndMillis = parsedStatsEndData[0]; + this.hidservV3StatsIntervalLength = parsedStatsEndData[1]; + } + + private void parseHidservRendV3RelayedCellsLine(String line, + String[] partsNoOpt) + throws DescriptorParseException { + if (partsNoOpt.length < 2) { + throw new DescriptorParseException("Illegal line '" + line + "'."); + } + try { + this.hidservRendV3RelayedCells = Double.parseDouble(partsNoOpt[1]); + } catch (NumberFormatException e) { + throw new DescriptorParseException("Illegal line '" + line + "'."); + } + this.hidservRendV3RelayedCellsParameters = + ParseHelper.parseSpaceSeparatedStringKeyDoubleValueMap(line, + partsNoOpt, 2); + } + + private void parseHidservDirV3OnionsSeenLine(String line, + String[] partsNoOpt) + throws DescriptorParseException { + if (partsNoOpt.length < 2) { + throw new DescriptorParseException("Illegal line '" + line + "'."); + } + try { + this.hidservDirV3OnionsSeen = Double.parseDouble(partsNoOpt[1]); + } catch (NumberFormatException e) { + throw new DescriptorParseException("Illegal line '" + line + "'."); + } + this.hidservDirV3OnionsSeenParameters = + ParseHelper.parseSpaceSeparatedStringKeyDoubleValueMap(line, + partsNoOpt, 2); + } + private void parsePaddingCountsLine(String line, String[] partsNoOpt) throws DescriptorParseException { long[] parsedStatsEndData = this.parseStatsEndLine(line, partsNoOpt, @@ -1319,6 +1368,50 @@ public abstract class ExtraInfoDescriptorImpl extends DescriptorImpl : new HashMap<>(this.hidservDirOnionsSeenParameters); }
+ private long hidservV3StatsEndMillis = -1L; + + @Override + public long getHidservV3StatsEndMillis() { + return this.hidservV3StatsEndMillis; + } + + private long hidservV3StatsIntervalLength = -1L; + + @Override + public long getHidservV3StatsIntervalLength() { + return this.hidservV3StatsIntervalLength; + } + + private Double hidservRendV3RelayedCells; + + @Override + public Double getHidservRendV3RelayedCells() { + return this.hidservRendV3RelayedCells; + } + + private Map<String, Double> hidservRendV3RelayedCellsParameters; + + @Override + public Map<String, Double> getHidservRendV3RelayedCellsParameters() { + return this.hidservRendV3RelayedCellsParameters == null ? null + : new HashMap<>(this.hidservRendV3RelayedCellsParameters); + } + + private Double hidservDirV3OnionsSeen; + + @Override + public Double getHidservDirV3OnionsSeen() { + return this.hidservDirV3OnionsSeen; + } + + private Map<String, Double> hidservDirV3OnionsSeenParameters; + + @Override + public Map<String, Double> getHidservDirV3OnionsSeenParameters() { + return this.hidservDirV3OnionsSeenParameters == null ? null + : new HashMap<>(this.hidservDirV3OnionsSeenParameters); + } + private long paddingCountsStatsEndMillis = -1L;
@Override diff --git a/src/main/java/org/torproject/descriptor/impl/Key.java b/src/main/java/org/torproject/descriptor/impl/Key.java index 70db350..b02d96e 100644 --- a/src/main/java/org/torproject/descriptor/impl/Key.java +++ b/src/main/java/org/torproject/descriptor/impl/Key.java @@ -90,8 +90,11 @@ public enum Key { HIBERNATING("hibernating"), HIDDEN_SERVICE_DIR("hidden-service-dir"), HIDSERV_DIR_ONIONS_SEEN("hidserv-dir-onions-seen"), + HIDSERV_DIR_V3_ONIONS_SEEN("hidserv-dir-v3-onions-seen"), HIDSERV_REND_RELAYED_CELLS("hidserv-rend-relayed-cells"), + HIDSERV_REND_V3_RELAYED_CELLS("hidserv-rend-v3-relayed-cells"), HIDSERV_STATS_END("hidserv-stats-end"), + HIDSERV_V3_STATS_END("hidserv-v3-stats-end"), ID("id"), IDENTITY_ED25519("identity-ed25519"), IPV6_CONN_BI_DIRECT("ipv6-conn-bi-direct"), diff --git a/src/test/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImplTest.java b/src/test/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImplTest.java index 1233bd5..08a5bc9 100644 --- a/src/test/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImplTest.java +++ b/src/test/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImplTest.java @@ -960,6 +960,16 @@ public class ExtraInfoDescriptorImplTest { hsb.buildHidservStatsLines()); }
+ private String hidservV3StatsEndLine = "hidserv-v3-stats-end 2020-11-30 " + + "12:00:00 (86400 s)"; + + private String hidservRendV3RelayedCellsLine + = "hidserv-rend-v3-relayed-cells 6920802 delta_f=2048 epsilon=0.30 " + + "bin_size=1024"; + + private String hidservDirV3OnionsSeenLine = "hidserv-dir-v3-onions-seen 28 " + + "delta_f=8 epsilon=0.30 bin_size=8"; + private static ExtraInfoDescriptor createWithDefaultLines() throws DescriptorParseException { return DescriptorBuilder.createWithHidservStatsLines( @@ -977,6 +987,15 @@ public class ExtraInfoDescriptorImplTest { if (this.hidservDirOnionsSeenLine != null) { sb.append(this.hidservDirOnionsSeenLine).append("\n"); } + if (this.hidservV3StatsEndLine != null) { + sb.append(this.hidservV3StatsEndLine).append("\n"); + } + if (this.hidservRendV3RelayedCellsLine != null) { + sb.append(this.hidservRendV3RelayedCellsLine).append("\n"); + } + if (this.hidservDirV3OnionsSeenLine != null) { + sb.append(this.hidservDirV3OnionsSeenLine).append("\n"); + } String lines = sb.toString(); if (lines.endsWith("\n")) { lines = lines.substring(0, lines.length() - 1); @@ -2170,6 +2189,33 @@ public class ExtraInfoDescriptorImplTest { assertTrue(params.isEmpty()); }
+ @Test + public void testHidservV3StatsValid() throws DescriptorParseException { + ExtraInfoDescriptor descriptor = HidservStatsBuilder + .createWithDefaultLines(); + assertEquals(1606737600000L, descriptor.getHidservV3StatsEndMillis()); + assertEquals(86400L, descriptor.getHidservV3StatsIntervalLength()); + assertEquals(6920802.0, descriptor.getHidservRendV3RelayedCells(), 0.0001); + Map<String, Double> params = + descriptor.getHidservRendV3RelayedCellsParameters(); + assertTrue(params.containsKey("delta_f")); + assertEquals(2048.0, params.remove("delta_f"), 0.0001); + assertTrue(params.containsKey("epsilon")); + assertEquals(0.3, params.remove("epsilon"), 0.0001); + assertTrue(params.containsKey("bin_size")); + assertEquals(1024.0, params.remove("bin_size"), 0.0001); + assertTrue(params.isEmpty()); + assertEquals(28.0, descriptor.getHidservDirV3OnionsSeen(), 0.0001); + params = descriptor.getHidservDirV3OnionsSeenParameters(); + assertTrue(params.containsKey("delta_f")); + assertEquals(8.0, params.remove("delta_f"), 0.0001); + assertTrue(params.containsKey("epsilon")); + assertEquals(0.3, params.remove("epsilon"), 0.0001); + assertTrue(params.containsKey("bin_size")); + assertEquals(8.0, params.remove("bin_size"), 0.0001); + assertTrue(params.isEmpty()); + } + @Test public void testHidservStatsEndLineMissing() throws DescriptorParseException {
tor-commits@lists.torproject.org