Parse version 3 onion service statistics lines.

Implements the library part of tpo/metrics/statistics#40002.
This commit is contained in:
Karsten Loesing 2020-12-08 10:40:19 +01:00
parent cf4830cac3
commit ee7c3eb738
5 changed files with 202 additions and 1 deletions

View File

@ -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 # Changes in version 2.14.0 - 2020-08-07

View File

@ -674,6 +674,61 @@ public interface ExtraInfoDescriptor extends Descriptor {
*/ */
Map<String, Double> getHidservDirOnionsSeenParameters(); 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 * Return the time in milliseconds since the epoch when the included
* padding-counts statistics ended, or -1 if no such statistics are included. * padding-counts statistics ended, or -1 if no such statistics are included.

View File

@ -225,6 +225,15 @@ public abstract class ExtraInfoDescriptorImpl extends DescriptorImpl
case HIDSERV_DIR_ONIONS_SEEN: case HIDSERV_DIR_ONIONS_SEEN:
this.parseHidservDirOnionsSeenLine(line, partsNoOpt); this.parseHidservDirOnionsSeenLine(line, partsNoOpt);
break; 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: case PADDING_COUNTS:
this.parsePaddingCountsLine(line, partsNoOpt); this.parsePaddingCountsLine(line, partsNoOpt);
break; break;
@ -764,6 +773,46 @@ public abstract class ExtraInfoDescriptorImpl extends DescriptorImpl
partsNoOpt, 2); 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, private void parsePaddingCountsLine(String line,
String[] partsNoOpt) throws DescriptorParseException { String[] partsNoOpt) throws DescriptorParseException {
long[] parsedStatsEndData = this.parseStatsEndLine(line, partsNoOpt, long[] parsedStatsEndData = this.parseStatsEndLine(line, partsNoOpt,
@ -1319,6 +1368,50 @@ public abstract class ExtraInfoDescriptorImpl extends DescriptorImpl
: new HashMap<>(this.hidservDirOnionsSeenParameters); : 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; private long paddingCountsStatsEndMillis = -1L;
@Override @Override

View File

@ -90,8 +90,11 @@ public enum Key {
HIBERNATING("hibernating"), HIBERNATING("hibernating"),
HIDDEN_SERVICE_DIR("hidden-service-dir"), HIDDEN_SERVICE_DIR("hidden-service-dir"),
HIDSERV_DIR_ONIONS_SEEN("hidserv-dir-onions-seen"), 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_RELAYED_CELLS("hidserv-rend-relayed-cells"),
HIDSERV_REND_V3_RELAYED_CELLS("hidserv-rend-v3-relayed-cells"),
HIDSERV_STATS_END("hidserv-stats-end"), HIDSERV_STATS_END("hidserv-stats-end"),
HIDSERV_V3_STATS_END("hidserv-v3-stats-end"),
ID("id"), ID("id"),
IDENTITY_ED25519("identity-ed25519"), IDENTITY_ED25519("identity-ed25519"),
IPV6_CONN_BI_DIRECT("ipv6-conn-bi-direct"), IPV6_CONN_BI_DIRECT("ipv6-conn-bi-direct"),

View File

@ -960,6 +960,16 @@ public class ExtraInfoDescriptorImplTest {
hsb.buildHidservStatsLines()); 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() private static ExtraInfoDescriptor createWithDefaultLines()
throws DescriptorParseException { throws DescriptorParseException {
return DescriptorBuilder.createWithHidservStatsLines( return DescriptorBuilder.createWithHidservStatsLines(
@ -977,6 +987,15 @@ public class ExtraInfoDescriptorImplTest {
if (this.hidservDirOnionsSeenLine != null) { if (this.hidservDirOnionsSeenLine != null) {
sb.append(this.hidservDirOnionsSeenLine).append("\n"); 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(); String lines = sb.toString();
if (lines.endsWith("\n")) { if (lines.endsWith("\n")) {
lines = lines.substring(0, lines.length() - 1); lines = lines.substring(0, lines.length() - 1);
@ -2170,6 +2189,33 @@ public class ExtraInfoDescriptorImplTest {
assertTrue(params.isEmpty()); 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 @Test
public void testHidservStatsEndLineMissing() public void testHidservStatsEndLineMissing()
throws DescriptorParseException { throws DescriptorParseException {