Commit 75844d04 authored by Karsten Loesing's avatar Karsten Loesing
Browse files

Parse "padding-counts" lines in extra-info descriptors.

Implements #22217.
parent f6252f90
......@@ -11,6 +11,7 @@
DescriptorParser and DescriptorReader and refer to
getUnrecognizedLines() in Descriptor if applications really need
to fail descriptors containing unrecognized lines.
- Parse "padding-counts" lines in extra-info descriptors.
* Minor changes
- Accept extra arguments in statistics-related extra-info
......
......@@ -649,6 +649,30 @@ public interface ExtraInfoDescriptor extends Descriptor {
*/
public Map<String, Double> getHidservDirOnionsSeenParameters();
/**
* Return the time in milliseconds since the epoch when the included
* padding-counts statistics ended, or -1 if no such statistics are included.
*
* @since 1.7.0
*/
public long getPaddingCountsStatsEndMillis();
/**
* Return the interval length of the included padding-counts statistics in
* seconds, or -1 if no such statistics are included.
*
* @since 1.7.0
*/
public long getPaddingCountsStatsIntervalLength();
/**
* Return padding-counts statistics, or <code>null</code> if no such
* statistics are included.
*
* @since 1.7.0
*/
public Map<String, Long> getPaddingCounts();
/**
* Return the RSA-1024 signature of the PKCS1-padded descriptor digest,
* taken from the beginning of the router line through the newline after
......
......@@ -66,6 +66,7 @@ public abstract class ExtraInfoDescriptorImpl extends DescriptorImpl
atMostOnceKeywords.addAll(connBiDirectStatsKeywords);
atMostOnceKeywords.addAll(exitStatsKeywords);
atMostOnceKeywords.addAll(bridgeStatsKeywords);
atMostOnceKeywords.add("padding-counts");
this.checkAtMostOnceKeywords(atMostOnceKeywords);
this.checkKeywordsDependOn(dirreqStatsKeywords, "dirreq-stats-end");
this.checkKeywordsDependOn(entryStatsKeywords, "entry-stats-end");
......@@ -220,6 +221,9 @@ public abstract class ExtraInfoDescriptorImpl extends DescriptorImpl
case "hidserv-dir-onions-seen":
this.parseHidservDirOnionsSeenLine(line, lineNoOpt, partsNoOpt);
break;
case "padding-counts":
this.parsePaddingCountsLine(line, lineNoOpt, partsNoOpt);
break;
case "identity-ed25519":
this.parseIdentityEd25519Line(line, lineNoOpt, partsNoOpt);
nextCrypto = "identity-ed25519";
......@@ -756,6 +760,16 @@ public abstract class ExtraInfoDescriptorImpl extends DescriptorImpl
partsNoOpt, 2);
}
private void parsePaddingCountsLine(String line, String lineNoOpt,
String[] partsNoOpt) throws DescriptorParseException {
long[] parsedStatsEndData = this.parseStatsEndLine(line, partsNoOpt,
6);
this.paddingCountsStatsEndMillis = parsedStatsEndData[0];
this.paddingCountsStatsIntervalLength = parsedStatsEndData[1];
this.paddingCounts = ParseHelper.parseSpaceSeparatedStringKeyLongValueMap(
line, partsNoOpt, 5);
}
private void parseRouterSignatureLine(String line, String lineNoOpt,
String[] partsNoOpt) throws DescriptorParseException {
if (!lineNoOpt.equals("router-signature")) {
......@@ -1341,6 +1355,28 @@ public abstract class ExtraInfoDescriptorImpl extends DescriptorImpl
: new HashMap<>(this.hidservDirOnionsSeenParameters);
}
private long paddingCountsStatsEndMillis = -1L;
@Override
public long getPaddingCountsStatsEndMillis() {
return this.paddingCountsStatsEndMillis;
}
private long paddingCountsStatsIntervalLength = -1L;
@Override
public long getPaddingCountsStatsIntervalLength() {
return this.paddingCountsStatsIntervalLength;
}
private Map<String, Long> paddingCounts;
@Override
public Map<String, Long> getPaddingCounts() {
return this.paddingCounts == null ? null
: new HashMap<>(this.paddingCounts);
}
private String routerSignature;
@Override
......
......@@ -493,6 +493,39 @@ public class ParseHelper {
return result;
}
protected static Map<String, Long>
parseSpaceSeparatedStringKeyLongValueMap(String line,
String[] partsNoOpt, int startIndex)
throws DescriptorParseException {
Map<String, Long> result = new LinkedHashMap<>();
if (partsNoOpt.length < startIndex) {
throw new DescriptorParseException("Line '" + line + "' does not "
+ "contain a key-value list starting at index " + startIndex
+ ".");
}
for (int i = startIndex; i < partsNoOpt.length; i++) {
String listElement = partsNoOpt[i];
String[] keyAndValue = listElement.split("=");
String key = null;
Long value = null;
if (keyAndValue.length == 2) {
try {
value = Long.parseLong(keyAndValue[1]);
key = keyAndValue[0];
} catch (NumberFormatException e) {
/* Handle below. */
}
}
if (key == null) {
throw new DescriptorParseException("Line '" + line + "' contains "
+ "an illegal key or value in list element '" + listElement
+ "'.");
}
result.put(key, value);
}
return result;
}
protected static String
parseMasterKeyEd25519FromIdentityEd25519CryptoBlock(
String identityEd25519CryptoBlock) throws DescriptorParseException {
......
......@@ -180,6 +180,15 @@ public class ExtraInfoDescriptorImplTest {
return new RelayExtraInfoDescriptorImpl(db.buildDescriptor(), true);
}
private String paddingCountsLine = null;
private static ExtraInfoDescriptor createWithPaddingCountsLine(
String line) throws DescriptorParseException {
DescriptorBuilder db = new DescriptorBuilder();
db.paddingCountsLine = line;
return new RelayExtraInfoDescriptorImpl(db.buildDescriptor(), true);
}
private String unrecognizedLine = null;
private static ExtraInfoDescriptor createWithUnrecognizedLine(
......@@ -288,6 +297,9 @@ public class ExtraInfoDescriptorImplTest {
if (this.hidservStatsLines != null) {
sb.append(this.hidservStatsLines).append("\n");
}
if (this.paddingCountsLine != null) {
sb.append(this.paddingCountsLine).append("\n");
}
if (this.unrecognizedLine != null) {
sb.append(this.unrecognizedLine).append("\n");
}
......@@ -1726,6 +1738,69 @@ public class ExtraInfoDescriptorImplTest {
"bridge-ip-transports obfs2=24 5");
}
@Test()
public void testPaddingCountsValid()
throws DescriptorParseException {
ExtraInfoDescriptor descriptor = DescriptorBuilder
.createWithPaddingCountsLine("padding-counts 2017-05-10 01:48:43 "
+ "(86400 s) bin-size=10000 write-drop=10000 write-pad=10000 "
+ "write-total=10000 read-drop=10000 read-pad=10000 read-total=70000 "
+ "enabled-read-pad=0 enabled-read-total=0 enabled-write-pad=0 "
+ "enabled-write-total=0 max-chanpad-timers=0");
assertEquals(1494380923000L,
descriptor.getPaddingCountsStatsEndMillis());
assertEquals(86400, descriptor.getPaddingCountsStatsIntervalLength());
assertEquals(10000L,
(long) descriptor.getPaddingCounts().get("bin-size"));
assertEquals(10000L,
(long) descriptor.getPaddingCounts().get("write-drop"));
assertEquals(10000L,
(long) descriptor.getPaddingCounts().get("write-pad"));
assertEquals(10000L,
(long) descriptor.getPaddingCounts().get("write-total"));
assertEquals(10000L,
(long) descriptor.getPaddingCounts().get("read-drop"));
assertEquals(10000L,
(long) descriptor.getPaddingCounts().get("read-pad"));
assertEquals(70000L,
(long) descriptor.getPaddingCounts().get("read-total"));
assertEquals(0L,
(long) descriptor.getPaddingCounts().get("enabled-read-pad"));
assertEquals(0L,
(long) descriptor.getPaddingCounts().get("enabled-read-total"));
assertEquals(0L,
(long) descriptor.getPaddingCounts().get("enabled-write-pad"));
assertEquals(0L,
(long) descriptor.getPaddingCounts().get("enabled-write-total"));
assertEquals(0L,
(long) descriptor.getPaddingCounts().get("max-chanpad-timers"));
}
@Test(expected = DescriptorParseException.class)
public void testPaddingCountsNoTime() throws DescriptorParseException {
DescriptorBuilder.createWithPaddingCountsLine("padding-counts 2017-05-10 "
+ "(86400 s) bin-size=10000 write-drop=10000");
}
@Test(expected = DescriptorParseException.class)
public void testPaddingCountsNoInterval() throws DescriptorParseException {
DescriptorBuilder.createWithPaddingCountsLine("padding-counts 2017-05-10 "
+ "01:48:43 bin-size=10000 write-drop=10000");
}
@Test(expected = DescriptorParseException.class)
public void testPaddingCountsCommaSeparatedList()
throws DescriptorParseException {
DescriptorBuilder.createWithPaddingCountsLine("padding-counts 2017-05-10 "
+ "(86400 s) bin-size=10000,write-drop=10000");
}
@Test(expected = DescriptorParseException.class)
public void testPaddingCountsNoList() throws DescriptorParseException {
DescriptorBuilder.createWithPaddingCountsLine("padding-counts 2017-05-10 "
+ "(86400 s)");
}
@Test()
public void testHidservStatsValid() throws DescriptorParseException {
ExtraInfoDescriptor descriptor = HidservStatsBuilder
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment