1use crate::{
8 parsers::MessageStream, DateTime, Greeting, HeaderValue, Host, Protocol, Received, TlsVersion,
9};
10use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13enum Token {
14 BracketOpen,
15 BracketClose,
16 AngleOpen,
17 AngleClose,
18 ParenthesisOpen,
19 ParenthesisClose,
20 Semicolon,
21 Colon,
22 Equal,
23 Slash,
24 Quote,
25 Comma,
26 IpAddr(IpAddr),
27 Integer(i64),
28 Text,
29 Domain,
30 Email,
31 Month(Month),
32 Protocol(Protocol),
33 Greeting(Greeting),
34 TlsVersion(TlsVersion),
35 Cipher,
36 By,
37 For,
38 From,
39 Id,
40 Via,
41 With,
42 Ident,
43}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46struct TokenData<'x> {
47 token: Token,
48 text: &'x str,
49 comment_depth: u32,
50 bracket_depth: u32,
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54enum Month {
55 Jan,
56 Feb,
57 Mar,
58 Apr,
59 May,
60 Jun,
61 Jul,
62 Aug,
63 Sep,
64 Oct,
65 Nov,
66 Dec,
67}
68
69struct Tokenizer<'x, 'y> {
70 stream: &'y mut MessageStream<'x>,
71 next_token: Option<TokenData<'x>>,
72 eof: bool,
73 in_quote: bool,
74 bracket_depth: u32,
75 comment_depth: u32,
76 in_date: bool,
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80enum State {
81 From,
82 By,
83 For,
84 Id,
85 With,
86 Via,
87 Date,
88 None,
89}
90
91impl<'x> MessageStream<'x> {
92 pub fn parse_received(&mut self) -> HeaderValue<'x> {
93 let mut tokenizer = Tokenizer::new(self).peekable();
96 let mut received = Received::default();
97
98 let mut state = State::None;
99 let mut date = [i64::MAX; 7];
100 let mut date_part = date.iter_mut();
101
102 while let Some(token) = tokenizer.next() {
103 match token.token {
104 Token::From if received.from.is_none() => {
105 while let Some(token) = tokenizer.peek() {
107 match token.token {
108 Token::BracketOpen => {
109 tokenizer.next();
110 }
111 Token::IpAddr(ip) => {
112 tokenizer.next();
113 received.from = Some(Host::IpAddr(ip));
114 break;
115 }
116 _ => {
117 if !token.token.is_separator() {
118 received.from =
119 Some(Host::Name(tokenizer.next().unwrap().text.into()));
120 }
121 break;
122 }
123 }
124 }
125 state = State::From;
126 }
127 Token::By if token.comment_depth == 0 => {
128 while let Some(token) = tokenizer.peek() {
130 match token.token {
131 Token::BracketOpen | Token::AngleOpen => {
132 tokenizer.next();
133 }
134 Token::IpAddr(ip) => {
135 tokenizer.next();
136 received.by = Some(Host::IpAddr(ip));
137 break;
138 }
139 _ => {
140 if !token.token.is_separator() {
141 received.by =
142 Some(Host::Name(tokenizer.next().unwrap().text.into()));
143 }
144 break;
145 }
146 }
147 }
148 state = State::By;
149 }
150 Token::For if token.comment_depth == 0 => {
151 while let Some(token) = tokenizer.peek() {
152 match token.token {
153 Token::Equal | Token::AngleOpen => {
154 tokenizer.next();
155 }
156 Token::Email => {
157 received.for_ = Some(tokenizer.next().unwrap().text.into());
158 break;
159 }
160 _ => {
161 break;
162 }
163 }
164 }
165 state = State::For;
166 }
167 Token::Semicolon if token.comment_depth == 0 => {
168 state = State::Date;
169 }
170 Token::Id if token.comment_depth == 0 => {
171 while let Some(token) = tokenizer.peek() {
172 match token.token {
173 Token::Equal | Token::AngleOpen | Token::BracketOpen | Token::Colon => {
174 tokenizer.next();
175 }
176 _ => {
177 if !token.token.is_separator() {
178 received.id = Some(tokenizer.next().unwrap().text.into());
179 }
180 break;
181 }
182 }
183 }
184 state = State::Id;
185 }
186 Token::With if token.comment_depth == 0 => {
187 while let Some(token) = tokenizer.peek() {
188 match token.token {
189 Token::Protocol(proto) => {
190 tokenizer.next();
191 received.with = Some(proto);
192 break;
193 }
194 Token::Semicolon
195 | Token::TlsVersion(_)
196 | Token::By
197 | Token::For
198 | Token::From
199 | Token::Id
200 | Token::Via
201 | Token::With => {
202 break;
203 }
204 _ => {
205 tokenizer.next();
206 }
207 }
208 }
209 state = State::With;
210 }
211 Token::Via if token.comment_depth == 0 => {
212 while let Some(token) = tokenizer.peek() {
213 match token.token {
214 Token::Equal => {
215 tokenizer.next();
216 }
217 _ => {
218 if !token.token.is_separator() {
219 received.via = Some(tokenizer.next().unwrap().text.into());
220 }
221 break;
222 }
223 }
224 }
225 state = State::Via;
226 }
227 Token::Ident if token.comment_depth > 0 => {
228 while let Some(token) = tokenizer.peek() {
229 match token.token {
230 Token::Equal | Token::AngleOpen | Token::BracketOpen | Token::Colon => {
231 tokenizer.next();
232 }
233 _ => {
234 if !token.token.is_separator() {
235 received.ident = Some(tokenizer.next().unwrap().text.into());
236 }
237 break;
238 }
239 }
240 }
241 }
242 Token::Greeting(greeting) if state == State::From && token.comment_depth > 0 => {
243 received.helo_cmd = Some(greeting);
245 while let Some(token) = tokenizer.peek() {
246 match token.token {
247 Token::Equal | Token::BracketOpen | Token::Colon => {
248 tokenizer.next();
249 }
250 Token::IpAddr(ip) => {
251 tokenizer.next();
252 received.helo = Some(Host::IpAddr(ip));
253 break;
254 }
255 _ => {
256 if !token.token.is_separator() {
257 received.helo =
258 Some(Host::Name(tokenizer.next().unwrap().text.into()));
259 }
260 break;
261 }
262 }
263 }
264 }
265 Token::IpAddr(ip)
266 if state == State::From
267 && (token.bracket_depth > 0
268 || (token.comment_depth > 0 && received.from_ip.is_none())) =>
269 {
270 received.from_ip = Some(ip);
271 }
272 Token::Domain if state == State::From && token.comment_depth > 0 => {
273 received.from_iprev = Some(token.text.into());
274 }
275 Token::Email if state == State::From => {
276 received.ident =
277 Some(token.text.strip_suffix('@').unwrap_or(token.text).into());
278 }
279 Token::Integer(num) if state == State::Date => {
280 if let Some(part) = date_part.next() {
281 *part = num;
282 }
283 }
284 Token::Month(month) if state == State::Date => {
285 if let Some(part) = date_part.next() {
286 *part = month.to_number();
287 }
288 }
289 Token::Cipher if token.comment_depth > 0 || received.tls_cipher.is_none() => {
290 received.tls_cipher = Some(token.text.into());
291 }
292 Token::TlsVersion(tls)
293 if token.comment_depth > 0 && received.tls_version.is_none() =>
294 {
295 received.tls_version = Some(tls);
296 }
297 _ => (),
298 }
299 }
300
301 if date[5] != i64::MAX {
302 let (tz, is_plus) = if date[6] != i64::MAX {
303 if date[6] < 0 {
304 (date[6].abs(), false)
305 } else {
306 (date[6], true)
307 }
308 } else {
309 (0, false)
310 };
311 received.date = DateTime {
312 year: if (1..=99).contains(&date[2]) {
313 date[2] + 1900
314 } else {
315 date[2]
316 } as u16,
317 month: date[1] as u8,
318 day: date[0] as u8,
319 hour: date[3] as u8,
320 minute: date[4] as u8,
321 second: date[5] as u8,
322 tz_hour: (tz / 100) as u8,
323 tz_minute: (tz % 100) as u8,
324 tz_before_gmt: !is_plus,
325 }
326 .into();
327 }
328
329 if received.from.is_some()
330 || received.from_ip.is_some()
331 || received.from_iprev.is_some()
332 || received.by.is_some()
333 || received.for_.is_some()
334 || received.with.is_some()
335 || received.tls_version.is_some()
336 || received.tls_cipher.is_some()
337 || received.id.is_some()
338 || received.ident.is_some()
339 || received.helo.is_some()
340 || received.helo_cmd.is_some()
341 || received.via.is_some()
342 || received.date.is_some()
343 {
344 HeaderValue::Received(Box::new(received))
345 } else {
346 HeaderValue::Empty
347 }
348 }
349}
350
351impl<'x> Iterator for Tokenizer<'x, '_> {
352 type Item = TokenData<'x>;
353
354 fn next(&mut self) -> Option<Self::Item> {
355 if let Some(next_token) = self.next_token.take() {
356 return Some(next_token);
357 } else if self.eof {
358 return None;
359 }
360 let mut n_alpha = 0; let mut n_digit = 0; let mut n_hex = 0; let mut n_dot = 0; let mut n_at = 0; let mut n_other = 0; let mut n_colon = 0; let mut n_plus = 0; let mut n_minus = 0; let mut n_utf = 0; let mut n_uppercase = 0;
371 let mut n_underscore = 0;
372
373 let mut n_total = 0;
374
375 let mut hash: u128 = 0;
376 let mut hash_shift = 0;
377
378 let comment_depth = self.comment_depth;
379 let bracket_depth = self.bracket_depth;
380
381 let mut start_pos = self.stream.offset();
382
383 while let Some(ch) = self.stream.next() {
384 match ch {
385 b'0'..=b'9' => {
386 n_digit += 1;
387 if hash_shift < 128 {
388 hash |= (*ch as u128) << hash_shift;
389 hash_shift += 8;
390 }
391 }
392 b'a'..=b'f' => {
393 n_hex += 1;
394 if hash_shift < 128 {
395 hash |= (*ch as u128) << hash_shift;
396 hash_shift += 8;
397 }
398 }
399 b'g'..=b'z' => {
400 n_alpha += 1;
401 if hash_shift < 128 {
402 hash |= (*ch as u128) << hash_shift;
403 hash_shift += 8;
404 }
405 }
406 b'A'..=b'F' => {
407 n_hex += 1;
408 n_uppercase += 1;
409 if hash_shift < 128 {
410 hash |= ((*ch - b'A' + b'a') as u128) << hash_shift;
411 hash_shift += 8;
412 }
413 }
414 b'G'..=b'Z' => {
415 n_alpha += 1;
416 n_uppercase += 1;
417 if hash_shift < 128 {
418 hash |= ((*ch - b'A' + b'a') as u128) << hash_shift;
419 hash_shift += 8;
420 }
421 }
422 b'@' => {
423 n_at += 1;
424 }
425 b'.' => {
426 n_dot += 1;
427 }
428 b'+' => {
429 n_plus += 1;
430 }
431 b'-' => {
432 n_minus += 1;
433 }
434 b'\n' => {
435 if !self.stream.try_next_is_space() {
436 self.eof = true;
437 break;
438 } else if n_total > 0 {
439 break;
440 } else {
441 start_pos = self.stream.offset();
442 }
443 }
444 b'(' => {
445 if !self.in_quote {
446 self.comment_depth = self.comment_depth.saturating_add(1);
447 }
448 self.next_token = Some(Token::ParenthesisOpen.into());
449 break;
450 }
451 b')' => {
452 if !self.in_quote {
453 self.comment_depth = self.comment_depth.saturating_sub(1);
454 }
455 self.next_token = Some(Token::ParenthesisClose.into());
456 break;
457 }
458 b'<' => {
459 self.next_token = Some(Token::AngleOpen.into());
460 break;
461 }
462 b'>' => {
463 self.next_token = Some(Token::AngleClose.into());
464 break;
465 }
466 b'[' => {
467 if !self.in_quote {
468 self.bracket_depth = self.comment_depth.saturating_add(1);
469 }
470 self.next_token = Some(Token::BracketOpen.into());
471 break;
472 }
473 b']' => {
474 if !self.in_quote {
475 self.bracket_depth = self.comment_depth.saturating_sub(1);
476 }
477 self.next_token = Some(Token::BracketClose.into());
478 break;
479 }
480 b':' => {
481 if self.in_date
483 || n_at > 0
484 || n_dot > 0
485 || n_alpha > 0
486 || n_other > 0
487 || n_plus > 0
488 || n_minus > 0
489 || n_utf > 0
490 || n_colon == 7
491 {
492 self.next_token = Some(Token::Colon.into());
493 break;
494 } else {
495 n_colon += 1;
496 }
497 }
498 b'=' => {
499 self.next_token = Some(Token::Equal.into());
500 break;
501 }
502 b';' => {
503 if self.comment_depth == 0 {
504 self.in_date = true;
505 }
506 self.next_token = Some(Token::Semicolon.into());
507 break;
508 }
509 b'/' => {
510 self.next_token = Some(Token::Slash.into());
511 break;
512 }
513 b'"' => {
514 self.in_quote = !self.in_quote;
515 self.next_token = Some(Token::Quote.into());
516 break;
517 }
518 b',' => {
519 self.next_token = Some(Token::Comma.into());
520 break;
521 }
522 b' ' | b'\t' | b'\r' => {
523 if n_total > 0 {
524 break;
525 } else {
526 start_pos += 1;
527 continue;
528 }
529 }
530 0x7f..=u8::MAX => {
531 n_utf += 1;
532 }
533 b'_' => {
534 n_underscore += 1;
535 n_other += 1;
536 }
537 _ => {
538 n_other += 1;
539 }
540 }
541
542 n_total += 1;
543 }
544
545 if n_total == 0 {
546 return self.next_token.take();
547 }
548
549 let text = std::str::from_utf8(self.stream.bytes(start_pos..self.stream.offset() - 1))
550 .unwrap_or_default();
551
552 let token = match (
553 n_alpha, n_digit, n_hex, n_dot, n_at, n_other, n_colon, n_plus, n_minus, n_utf, hash,
554 ) {
555 (0, 4..=12, 0, 3, 0, 0, 0, 0, 0, 0, _) => {
556 text.parse::<Ipv4Addr>()
558 .map(|ip| Token::IpAddr(IpAddr::V4(ip)))
559 .unwrap_or(Token::Text)
560 }
561 (0, _, 1..=32, 0, 0, 0, 2.., 0, 0, 0, _)
562 | (0, 1..=32, _, 0, 0, 0, 2.., 0, 0, 0, _)
563 | (0, 4..=12, 4, 3, 0, 0, 3, 0, 0, 0, _) => {
564 text.parse::<Ipv6Addr>()
566 .map(|ip| Token::IpAddr(IpAddr::V6(ip)))
567 .unwrap_or(Token::Text)
568 }
569 (0, 1.., 0, 0, 0, 0, 0, 0, 0, 0, _)
570 | (0, 1.., 0, 0, 0, 0, 0, 0, 1, 0, _)
571 | (0, 1.., 0, 0, 0, 0, 0, 1, 0, 0, _) => {
572 text.parse::<i64>()
574 .map(Token::Integer)
575 .unwrap_or(Token::Text)
576 }
577 (1.., _, _, _, 1, _, _, _, _, _, _) | (_, _, 1.., _, 1, _, _, _, _, _, _) => {
578 Token::Email
580 }
581 (2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x727061) => Token::Month(Month::Apr),
582 (4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x70746d7362) => Token::Protocol(Protocol::SMTP),
583 (1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x7962) => Token::By,
584 (0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0x636564) => Token::Month(Month::Dec),
585 (3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x6f6c6865) => Token::Greeting(Greeting::Ehlo),
586 (4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x70746d7365) => Token::Protocol(Protocol::ESMTP),
587 (4, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0x6170746d7365) => Token::Protocol(Protocol::ESMTPA),
588 (5, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x7370746d7365) => Token::Protocol(Protocol::ESMTPS),
589 (2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x726f66) => Token::For,
590 (3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x6d6f7266) => Token::From,
591 (3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x6f6c6568) => Token::Greeting(Greeting::Helo),
592 (4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x70747468) => Token::Protocol(Protocol::HTTP),
593 (7, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x7473657270747468) => Token::Protocol(Protocol::HTTP),
594 (1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x6469) => Token::Id,
595 (3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x70616d69) => Token::Protocol(Protocol::IMAP),
596 (2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x6e616a) => Token::Month(Month::Jan),
597 (3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x6c756a) => Token::Month(Month::Jul),
598 (3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x6e756a) => Token::Month(Month::Jun),
599 (4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x6f6c686c) => Token::Greeting(Greeting::Lhlo),
600 (4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x70746d6c) => Token::Protocol(Protocol::LMTP),
601 (4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x6170746d6c) => Token::Protocol(Protocol::LMTPA),
602 (3, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0x6c61636f6c) => Token::Protocol(Protocol::Local),
603 (5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x70746d736c) => Token::Protocol(Protocol::LMTP),
604 (2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x72616d) => Token::Month(Month::Mar),
605 (2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x79616d) => Token::Month(Month::May),
606 (3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x766f6e) => Token::Month(Month::Nov),
607 (3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0x33706f70) => Token::Protocol(Protocol::POP3),
608 (2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x706573) => Token::Month(Month::Sep),
609 (4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x70746d73) => Token::Protocol(Protocol::SMTP),
610 (4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x6470746d73) => Token::Protocol(Protocol::SMTP),
611 (6, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x63767370746d73) => Token::Protocol(Protocol::SMTP),
612 (4, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0x74656b636f73) => Token::Protocol(Protocol::Local),
613 (4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x6e69647473) => Token::Protocol(Protocol::Local),
614 (2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x616976) => Token::Via,
615 (0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0x626566) => Token::Month(Month::Feb),
616 (2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x677561) => Token::Month(Month::Aug),
617 (2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x74636f) => Token::Month(Month::Oct),
618 (4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x68746977) => Token::With,
619 (4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x70746d7361) => Token::Protocol(Protocol::ESMTPA),
620 (5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x7570747468) => Token::Protocol(Protocol::HTTP),
621 (5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x7370747468) => Token::Protocol(Protocol::HTTPS),
622 (3, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0x746e656469) => Token::Ident,
623 (5, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0x617370746d7365) => Token::Protocol(Protocol::ESMTPSA),
624 (5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x7370746d6c) => Token::Protocol(Protocol::LMTPS),
625 (5, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x617370746d6c) => Token::Protocol(Protocol::LMTPSA),
626 (3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x736d6d) => Token::Protocol(Protocol::MMS),
627 (6, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0x70746d7338667475) => {
628 Token::Protocol(Protocol::UTF8SMTP)
629 }
630 (6, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0x6170746d7338667475) => {
631 Token::Protocol(Protocol::UTF8SMTPA)
632 }
633 (7, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0x7370746d7338667475) => {
634 Token::Protocol(Protocol::UTF8SMTPS)
635 }
636 (7, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0x617370746d7338667475) => {
637 Token::Protocol(Protocol::UTF8SMTPSA)
638 }
639 (6, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0x70746d6c38667475) => {
640 Token::Protocol(Protocol::UTF8LMTP)
641 }
642 (6, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0x6170746d6c38667475) => {
643 Token::Protocol(Protocol::UTF8LMTPA)
644 }
645 (7, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0x7370746d6c38667475) => {
646 Token::Protocol(Protocol::UTF8LMTPS)
647 }
648 (7, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0x617370746d6c38667475) => {
649 Token::Protocol(Protocol::UTF8LMTPSA)
650 }
651 (7, 0, 3, 0, 0, 0, 0, 0, _, 0, 0x70746d73656c61636f6c) => {
652 Token::Protocol(Protocol::ESMTP)
653 }
654 (8, 0, 3, 0, 0, 0, 0, 0, _, 0, 0x7370746d73656c61636f6c) => {
655 Token::Protocol(Protocol::ESMTPS)
656 }
657 (7, 0, 3, 0, 0, 0, 0, 0, _, 0, 0x70746d73626c61636f6c) => {
658 Token::Protocol(Protocol::SMTP)
659 }
660 (7, 0, 1, 0, 0, 0, 0, 0, _, 0, 0x736c7470746d7365) => Token::Protocol(Protocol::ESMTPS),
661 (3, 2, 0, _, 0, _, 0, 0, _, 0, 0x3031736c74) => Token::TlsVersion(TlsVersion::TLSv1_0),
662 (3, 2, 0, _, 0, _, 0, 0, _, 0, 0x3131736c74) => Token::TlsVersion(TlsVersion::TLSv1_1),
663 (3, 2, 0, _, 0, _, 0, 0, _, 0, 0x3231736c74) => Token::TlsVersion(TlsVersion::TLSv1_2),
664 (3, 2, 0, _, 0, _, 0, 0, _, 0, 0x3331736c74) => Token::TlsVersion(TlsVersion::TLSv1_3),
665 (4, 2, 0, _, 0, _, 0, 0, 0, 0, 0x303176736c74) => {
666 Token::TlsVersion(TlsVersion::TLSv1_0)
667 }
668 (4, 2, 0, _, 0, _, 0, 0, 0, 0, 0x313176736c74) => {
669 Token::TlsVersion(TlsVersion::TLSv1_1)
670 }
671 (4, 2, 0, _, 0, _, 0, 0, 0, 0, 0x323176736c74) => {
672 Token::TlsVersion(TlsVersion::TLSv1_2)
673 }
674 (4, 2, 0, _, 0, _, 0, 0, 0, 0, 0x333176736c74) => {
675 Token::TlsVersion(TlsVersion::TLSv1_3)
676 }
677 (3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0x326c7373) => Token::TlsVersion(TlsVersion::SSLv2),
678 (3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0x336c7373) => Token::TlsVersion(TlsVersion::SSLv3),
679 (4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0x32766c7373) => Token::TlsVersion(TlsVersion::SSLv2),
680 (4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0x33766c7373) => Token::TlsVersion(TlsVersion::SSLv3),
681 (3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0x31736c74) => Token::TlsVersion(TlsVersion::TLSv1_0),
682 (4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0x3176736c74) => Token::TlsVersion(TlsVersion::TLSv1_0),
683 (4, 2, 1, _, 0, _, 0, 0, 0, 0, 0x303176736c7464) => {
684 Token::TlsVersion(TlsVersion::DTLSv1_0)
685 }
686 (4, 2, 1, _, 0, _, 0, 0, 0, 0, 0x323176736c7464) => {
687 Token::TlsVersion(TlsVersion::DTLSv1_2)
688 }
689 (4, 2, 1, _, 0, _, 0, 0, 0, 0, 0x333176736c7464) => {
690 Token::TlsVersion(TlsVersion::DTLSv1_3)
691 }
692 (3, 2, 1, _, 0, _, 0, 0, 0, 0, 0x3031736c7464) => {
693 Token::TlsVersion(TlsVersion::DTLSv1_0)
694 }
695 (3, 2, 1, _, 0, _, 0, 0, 0, 0, 0x3231736c7464) => {
696 Token::TlsVersion(TlsVersion::DTLSv1_2)
697 }
698 (3, 2, 1, _, 0, _, 0, 0, 0, 0, 0x3331736c7464) => {
699 Token::TlsVersion(TlsVersion::DTLSv1_3)
700 }
701 (1.., _, _, 1.., 0, 0, 0, 0, _, _, _) | (_, _, 1.., 1.., 0, 0, 0, 0, _, _, _) => {
702 Token::Domain
704 }
705 _ => {
706 if n_alpha + n_hex == n_uppercase
708 && n_total > 6
709 && (n_underscore > 0 || n_minus > 0)
710 && n_digit > 0
711 && n_dot == 0
712 && n_at == 0
713 && n_plus == 0
714 && (n_other == 0 || n_other == n_underscore)
715 && n_colon == 0
716 && n_utf == 0
717 && [
718 0x617372, 0x646365, 0x646365, 0x656864, 0x6b7370, 0x707273, 0x736561,
719 0x736564, 0x736c74,
720 ]
721 .contains(&(hash & 0xffffff))
722 {
723 Token::Cipher
724 } else {
725 Token::Text
726 }
727 }
728 };
729
730 TokenData {
731 text,
732 token,
733 comment_depth,
734 bracket_depth,
735 }
736 .into()
737 }
738}
739
740impl<'x, 'y> Tokenizer<'x, 'y> {
741 fn new(stream: &'y mut MessageStream<'x>) -> Self {
742 Self {
743 stream,
744 next_token: None,
745 eof: false,
746 in_quote: false,
747 bracket_depth: 0,
748 comment_depth: 0,
749 in_date: false,
750 }
751 }
752}
753
754impl From<Token> for TokenData<'_> {
755 fn from(token: Token) -> Self {
756 Self {
757 token,
758 text: "",
759 comment_depth: 0,
760 bracket_depth: 0,
761 }
762 }
763}
764
765impl Month {
766 fn to_number(self) -> i64 {
767 match self {
768 Month::Jan => 1,
769 Month::Feb => 2,
770 Month::Mar => 3,
771 Month::Apr => 4,
772 Month::May => 5,
773 Month::Jun => 6,
774 Month::Jul => 7,
775 Month::Aug => 8,
776 Month::Sep => 9,
777 Month::Oct => 10,
778 Month::Nov => 11,
779 Month::Dec => 12,
780 }
781 }
782}
783
784impl Token {
785 fn is_separator(&self) -> bool {
786 matches!(
787 self,
788 Token::BracketOpen
789 | Token::BracketClose
790 | Token::AngleOpen
791 | Token::AngleClose
792 | Token::ParenthesisOpen
793 | Token::ParenthesisClose
794 | Token::Semicolon
795 | Token::Colon
796 | Token::Equal
797 | Token::Slash
798 | Token::Quote
799 | Token::Comma
800 )
801 }
802}
803
804#[cfg(test)]
805mod tests {
806
807 use crate::parsers::{fields::load_tests, MessageStream};
808
809 #[test]
810 fn parse_received() {
811 for test in load_tests("received.json") {
812 assert_eq!(
813 MessageStream::new(test.header.as_bytes())
814 .parse_received()
815 .unwrap_received(),
816 test.expected,
817 "failed for {:?}",
818 test.header
819 );
820 }
821 }
822}