From 624843668aecaedc481bf3ac20842ddbec9ca25e Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sun, 7 Jun 2020 18:57:26 -0400 Subject: [PATCH] netdoc: add an iterator that can parse annotated microdescs --- tor-netdoc/src/microdesc.rs | 89 +++++++++++++++++++++++++++++- tor-netdoc/testdata/microdesc2.txt | 39 +++++++++++++ 2 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 tor-netdoc/testdata/microdesc2.txt diff --git a/tor-netdoc/src/microdesc.rs b/tor-netdoc/src/microdesc.rs index 3b2742418..c26d9369a 100644 --- a/tor-netdoc/src/microdesc.rs +++ b/tor-netdoc/src/microdesc.rs @@ -48,6 +48,15 @@ pub struct Microdesc { // pr is obsolete and doesn't go here any more. } +/// A microdescriptor annotated with additional data +/// +/// TODO: rename this. +#[allow(dead_code)] +pub struct AnnotatedMicrodesc { + md: Microdesc, + ann: MicrodescAnnotation, +} + decl_keyword! { /// Keyword type for recognized objects in microdescriptors. MicrodescKW { @@ -84,6 +93,12 @@ lazy_static! { }; } +impl Default for MicrodescAnnotation { + fn default() -> Self { + MicrodescAnnotation { last_listed: None } + } +} + impl MicrodescAnnotation { #[allow(dead_code)] fn parse_from_reader( @@ -206,14 +221,86 @@ impl Microdesc { }) } } + +/// An iterator that parses one or more (possible annnotated) +/// microdescriptors from a string. +pub struct MicrodescReader<'a> { + annotated: bool, + reader: NetDocReader<'a, MicrodescKW>, +} + +/// Indicates whether we should parse an annotated list of votes or a +/// non-annotated list. +/// +/// TODO: Move this. +#[derive(PartialEq, Debug)] +pub enum AllowAnnotations { + /// Parsing a document where items might be annotated. + /// + /// Annotations are a list of zero or more items with keywords + /// beginning with @ that precede the items that are actually part + /// of the document. + AnnotationsAllowed, + /// Parsing a document where annotations are not allowed. + AnnotationsNotAllowed, +} + +impl<'a> MicrodescReader<'a> { + /// Construct a MicrodescReader to take microdescriptors from a string + /// 's'. + pub fn new(s: &'a str, allow: AllowAnnotations) -> Self { + let reader = NetDocReader::new(s); + let annotated = allow == AllowAnnotations::AnnotationsAllowed; + MicrodescReader { annotated, reader } + } + + fn take_annotation(&mut self) -> Result { + if self.annotated { + MicrodescAnnotation::parse_from_reader(&mut self.reader) + } else { + Ok(MicrodescAnnotation::default()) + } + } + + fn take_annotated_microdesc(&mut self) -> Result { + let ann = self.take_annotation()?; + let md = Microdesc::parse_from_reader(&mut self.reader)?; + Ok(AnnotatedMicrodesc { md, ann }) + // TODO need to advance to next likely md. + } +} + +impl<'a> Iterator for MicrodescReader<'a> { + type Item = Result; + fn next(&mut self) -> Option { + // If there is no next token, we're at the end. + self.reader.iter().peek()?; + + Some(self.take_annotated_microdesc()) + } +} + #[cfg(test)] mod test { use super::*; const TESTDATA: &str = include_str!("../testdata/microdesc1.txt"); + const TESTDATA2: &str = include_str!("../testdata/microdesc2.txt"); #[test] - fn parse_arbitrary() -> Result<()> { + fn parse_single() -> Result<()> { let _md = Microdesc::parse(TESTDATA)?; Ok(()) } + + #[test] + fn parse_multi() -> Result<()> { + let mut n: u32 = 0; + for md in MicrodescReader::new(TESTDATA2, AllowAnnotations::AnnotationsAllowed) { + md?; + n += 1; + } + assert_eq!(n, 4); + Ok(()) + // TODO: test actual contents. + } } diff --git a/tor-netdoc/testdata/microdesc2.txt b/tor-netdoc/testdata/microdesc2.txt new file mode 100644 index 000000000..c575dabfc --- /dev/null +++ b/tor-netdoc/testdata/microdesc2.txt @@ -0,0 +1,39 @@ +@last-listed 2020-01-27 18:52:09 +onion-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBAMaCi6KwIpOaPFhyMJsJC+r516p0kZXnEuaJLgSR5uakJDW31qDlwD29 +dDLBwT4RmiD+OPNSjBpdEIJDbaDNGdgQLpdLgpl7v5ONoOQ3cRlbySOLmZ/7fYeW +DE+4eDLemIqU2e3lEOnb/bpCdQ309FX5OiKDcNy8tqtWgoOdOE0/AgMBAAE= +-----END RSA PUBLIC KEY----- +ntor-onion-key XoldZTBKOhiUYWZgFD969XV/4IvBgEXHhV7o3ruebEc= +family $06804E6383EE94E83C9453F39B1E524C272D6D84 $0D12D8E72DED99EE31BB0C57789352BED0CEEEFF $113143469021882C3A4B82F084F8125B08EE471E $4BFC9C631A93FF4BA3AA84BC6931B4310C38A263 $530277866466A1425F43A73DBFCB5FC7410C9852 $5BA19B5D5AB0CB9EF8EA33DA77585B75449400B0 $763B7D67A6B2D19B3E9EA57D1FBDC48F3B85B559 $7AA7FC80E3E0D32E929D2CC094EACF529C95264C $8CF987FF43FB7F3D9AA4C4F3D96FFDF247A9A6C2 $9661AC95717798884F3E3727D360DD98D66727CC $96E095D5CDBFC3988DEB708EC155346472402C32 $97AEE1EEFBCBB6FF8FA482029830E8E10A961883 $B1045E12FA4EA0D457A74013866CB41DC0D290BF $B27CF1DCEECD50F7992B07D720D7F6BF0EDF9D40 $BE0AC3B6692085308CA766F9E03736D1CAAED6F3 $C282248597D1C8522A2A7525E61C8B77BBC37614 $C8AE26D4819504D0157AD4C5DE7D5A0A7E190D10 $D24D0C28AB48768CF8B79DD762D61DB4FD015677 $DE847D94E78B2E560AB87D272DC90192D3144F17 $F34E681AF8226DEBC9135A48F61DEF9F68966BA5 $FEDF4998951A750D5D7974DF243035499E84882E +p accept 43,80,443,853,873,993,995,1194,2086,3128,5222-5223,5269,8000,8008,8080,8232-8233,8443,8888,9418,11371 +p6 accept 43,80,443,853,873,993,995,1194,2086,3128,5222-5223,5269,8000,8008,8080,8232-8233,8443,8888,9418,11371 +id ed25519 LYX9yI5sG8+0aJf8odum0TVPkyYdaKeeC1vBcN2SMIQ +@last-listed 2020-01-27 18:52:09 +onion-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBAMJi4/MtSJv4lYgLfq+z+2S90cGwIJJfp/mIxx0wX/q7jX6MWGG4+NQx +gofp3zxAEgglTfdTsvFFzQN4PjVkuwyFmmcYukVmS86e35nmPT3Yq3DPSXBRCtX5 +mMXC68bQT+npnPnoafxMdQddWCATkSD8wBrUKix4nOOaOcoD73SfAgMBAAE= +-----END RSA PUBLIC KEY----- +ntor-onion-key siPT+/px5J0pgsTdAWxCNRHbghZ98E6QY2Ioxl7Y2x0= +id ed25519 eQEthL1Cz57iO7GZ8RtS5lNiBVGCW9KH+VCBpOikywc +@last-listed 2020-01-27 18:52:10 +onion-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBALWooFgPxb0v6TR6PtAlLZWQ5vsX8oTJCiD4yg1bPv2MA2KnquQj+lys +H0yh/8MH814J/qFkjgTFt7An3U5VRnOyD9BAAJuT7FsqAFTlPzn2hK/PliE/K2/N +XMeaV6brBOcYvhMR9EWV+zBRpvkkQWqSqNlVjZi78fD1s/y0TjzTAgMBAAE= +-----END RSA PUBLIC KEY----- +ntor-onion-key mp9h+hzj2D18B/dLvu4RlEaTktzqrSThY5hc0cSEoBg= +id ed25519 3B+5CwspC+alleI5eA7jvxp6aGBC8QvF1D3wKBSwEDQ +@last-listed 2020-01-27 18:52:09 +onion-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBAMESE/ElGU2kyaq0VJ7mwGvns6mhMm75ZyYDbR+Eaa3b18PVOslR4aEv +3RJAt9N4Ph7N2VHZHVxwPKWViVDhZNMvOD5PJLb587KmTvD77Eo6MSh6umxy6xvo +GfgJJlyrlBQdvxRZVfEmUvjdZixbJUCI9ydxQG7hBk1n89dgLnTJAgMBAAE= +-----END RSA PUBLIC KEY----- +ntor-onion-key wcEKLkC4GnqCN0LJxRecweZgYmTg4whSxzFmhAmJYGQ= +id ed25519 1az7VeHFAgB0KwtxH+nQJSi3dw8rIl4iT5sMqeodTDg