1use anyhow::{Context as _, Result};
44use std::collections::HashMap;
45use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
46use std::str::FromStr;
47use std::sync::LazyLock;
48use tokio::net::lookup_host;
49use tokio::time::timeout;
50
51use super::load_connection_timestamp;
52use crate::context::Context;
53use crate::log::warn;
54use crate::tools::time;
55
56async fn update_cache(context: &Context, host: &str, addr: &str, now: i64) -> Result<()> {
59 context
60 .sql
61 .execute(
62 "INSERT INTO dns_cache
63 (hostname, address, timestamp)
64 VALUES (?, ?, ?)
65 ON CONFLICT (hostname, address)
66 DO UPDATE SET timestamp=excluded.timestamp",
67 (host, addr, now),
68 )
69 .await?;
70 Ok(())
71}
72
73pub(crate) async fn prune_dns_cache(context: &Context) -> Result<()> {
74 let now = time();
75 context
76 .sql
77 .execute(
78 "DELETE FROM dns_cache
79 WHERE ? > timestamp + ?",
80 (now, super::CACHE_TTL),
81 )
82 .await?;
83 Ok(())
84}
85
86static LOOKUP_HOST_CACHE: LazyLock<parking_lot::RwLock<HashMap<String, Vec<IpAddr>>>> =
95 LazyLock::new(Default::default);
96
97async fn lookup_ips(host: impl tokio::net::ToSocketAddrs) -> Result<impl Iterator<Item = IpAddr>> {
99 Ok(lookup_host(host)
100 .await
101 .context("DNS lookup failure")?
102 .map(|addr| addr.ip()))
103}
104
105async fn lookup_host_with_memory_cache(
106 context: &Context,
107 hostname: &str,
108 port: u16,
109) -> Result<Vec<IpAddr>> {
110 let stale_result = {
111 let rwlock_read_guard = LOOKUP_HOST_CACHE.read();
112 rwlock_read_guard.get(hostname).cloned()
113 };
114 if let Some(stale_result) = stale_result {
115 {
117 let context = context.clone();
118 let hostname = hostname.to_string();
119 tokio::spawn(async move {
120 match lookup_ips((hostname.clone(), port)).await {
121 Ok(res) => {
122 LOOKUP_HOST_CACHE.write().insert(hostname, res.collect());
123 }
124 Err(err) => {
125 warn!(
126 context,
127 "Failed to revalidate results for {hostname:?}: {err:#}."
128 );
129 }
130 }
131 });
132 }
133
134 info!(
135 context,
136 "Using memory-cached DNS resolution for {hostname}."
137 );
138 Ok(stale_result)
139 } else {
140 info!(
141 context,
142 "No memory-cached DNS resolution for {hostname} available, waiting for the resolver."
143 );
144 let res: Vec<IpAddr> = lookup_ips((hostname, port)).await?.collect();
145
146 LOOKUP_HOST_CACHE
151 .write()
152 .insert(hostname.to_string(), res.clone());
153 Ok(res)
154 }
155}
156
157async fn lookup_host_and_update_cache(
160 context: &Context,
161 hostname: &str,
162 port: u16,
163 now: i64,
164) -> Result<Vec<SocketAddr>> {
165 let res: Vec<IpAddr> = timeout(
166 super::TIMEOUT,
167 lookup_host_with_memory_cache(context, hostname, port),
168 )
169 .await
170 .context("DNS lookup timeout")?
171 .context("DNS lookup with memory cache failure")?;
172
173 for ip in &res {
174 let ip_string = ip.to_string();
175 if ip_string == hostname {
176 continue;
178 }
179
180 info!(context, "Resolved {hostname} into {ip}.");
181
182 update_cache(context, hostname, &ip_string, now).await?;
184 }
185
186 let res = res
187 .into_iter()
188 .map(|ip| SocketAddr::new(ip, port))
189 .collect();
190 Ok(res)
191}
192
193pub(crate) async fn update_connect_timestamp(
208 context: &Context,
209 host: &str,
210 address: &str,
211) -> Result<()> {
212 if host == address {
213 return Ok(());
214 }
215
216 context
217 .sql
218 .execute(
219 "INSERT INTO dns_cache (hostname, address, timestamp)
220 VALUES (?, ?, ?)
221 ON CONFLICT (hostname, address)
222 DO UPDATE SET timestamp=excluded.timestamp",
223 (host, address, time()),
224 )
225 .await?;
226 Ok(())
227}
228
229static DNS_PRELOAD: LazyLock<HashMap<&'static str, Vec<IpAddr>>> = LazyLock::new(|| {
231 HashMap::from([
232 (
233 "imap.163.com",
234 vec![IpAddr::V4(Ipv4Addr::new(111, 124, 203, 45))],
235 ),
236 (
237 "smtp.163.com",
238 vec![IpAddr::V4(Ipv4Addr::new(103, 129, 252, 45))],
239 ),
240 (
241 "newyear.aktivix.org",
242 vec![IpAddr::V4(Ipv4Addr::new(209, 51, 180, 245))],
243 ),
244 (
245 "smtp.aliyun.com",
246 vec![IpAddr::V4(Ipv4Addr::new(47, 246, 136, 232))],
247 ),
248 (
249 "imap.aliyun.com",
250 vec![
251 IpAddr::V4(Ipv4Addr::new(59, 82, 43, 123)),
252 IpAddr::V4(Ipv4Addr::new(59, 82, 9, 176)),
253 ],
254 ),
255 (
256 "imap.aol.com",
257 vec![
258 IpAddr::V4(Ipv4Addr::new(212, 82, 101, 33)),
259 IpAddr::V4(Ipv4Addr::new(87, 248, 98, 69)),
260 ],
261 ),
262 (
263 "imap.arcor.de",
264 vec![
265 IpAddr::V4(Ipv4Addr::new(178, 15, 69, 210)),
266 IpAddr::V4(Ipv4Addr::new(151, 189, 176, 206)),
267 ],
268 ),
269 (
270 "smtp.aol.com",
271 vec![IpAddr::V4(Ipv4Addr::new(87, 248, 97, 31))],
272 ),
273 (
274 "mail.arcor.de",
275 vec![
276 IpAddr::V4(Ipv4Addr::new(151, 189, 176, 206)),
277 IpAddr::V4(Ipv4Addr::new(178, 15, 69, 206)),
278 ],
279 ),
280 (
281 "mail.autistici.org",
282 vec![
283 IpAddr::V4(Ipv4Addr::new(93, 190, 126, 19)),
284 IpAddr::V4(Ipv4Addr::new(185, 218, 207, 228)),
285 IpAddr::V4(Ipv4Addr::new(198, 167, 222, 108)),
286 ],
287 ),
288 (
289 "smtp.autistici.org",
290 vec![
291 IpAddr::V4(Ipv4Addr::new(82, 94, 249, 234)),
292 IpAddr::V4(Ipv4Addr::new(93, 190, 126, 19)),
293 IpAddr::V4(Ipv4Addr::new(198, 167, 222, 108)),
294 ],
295 ),
296 (
297 "imaps.bluewin.ch",
298 vec![
299 IpAddr::V4(Ipv4Addr::new(16, 62, 253, 42)),
300 IpAddr::V4(Ipv4Addr::new(16, 63, 141, 244)),
301 IpAddr::V4(Ipv4Addr::new(16, 63, 146, 183)),
302 ],
303 ),
304 (
305 "smtpauths.bluewin.ch",
306 vec![
307 IpAddr::V4(Ipv4Addr::new(16, 62, 176, 232)),
308 IpAddr::V4(Ipv4Addr::new(16, 62, 15, 25)),
309 IpAddr::V4(Ipv4Addr::new(16, 63, 183, 216)),
310 ],
311 ),
312 (
313 "mail.buzon.uy",
314 vec![IpAddr::V4(Ipv4Addr::new(200, 40, 115, 74))],
315 ),
316 (
317 "daleth.cafe",
318 vec![IpAddr::V4(Ipv4Addr::new(37, 27, 6, 204))],
319 ),
320 (
321 "disroot.org",
322 vec![IpAddr::V4(Ipv4Addr::new(178, 21, 23, 139))],
323 ),
324 (
325 "imap.fastmail.com",
326 vec![
327 IpAddr::V4(Ipv4Addr::new(103, 168, 172, 43)),
328 IpAddr::V4(Ipv4Addr::new(103, 168, 172, 58)),
329 ],
330 ),
331 (
332 "smtp.fastmail.com",
333 vec![
334 IpAddr::V4(Ipv4Addr::new(103, 168, 172, 45)),
335 IpAddr::V4(Ipv4Addr::new(103, 168, 172, 60)),
336 ],
337 ),
338 (
339 "imap.gmail.com",
340 vec![
341 IpAddr::V4(Ipv4Addr::new(142, 250, 110, 108)),
342 IpAddr::V4(Ipv4Addr::new(142, 250, 110, 109)),
343 IpAddr::V4(Ipv4Addr::new(66, 102, 1, 108)),
344 IpAddr::V4(Ipv4Addr::new(66, 102, 1, 109)),
345 IpAddr::V6(Ipv6Addr::new(0x2a00, 0x1450, 0x400c, 0xc1f, 0, 0, 0, 0x6c)),
346 IpAddr::V6(Ipv6Addr::new(0x2a00, 0x1450, 0x400c, 0xc1f, 0, 0, 0, 0x6d)),
347 ],
348 ),
349 (
350 "mail.ecloud.global",
351 vec![IpAddr::V4(Ipv4Addr::new(95, 217, 246, 96))],
352 ),
353 (
354 "mail.ende.in.net",
355 vec![IpAddr::V4(Ipv4Addr::new(95, 217, 5, 72))],
356 ),
357 (
358 "smtp.gmail.com",
359 vec![
360 IpAddr::V4(Ipv4Addr::new(142, 250, 110, 109)),
361 IpAddr::V6(Ipv6Addr::new(0x2a00, 0x1450, 0x4013, 0xc04, 0, 0, 0, 0x6c)),
362 ],
363 ),
364 (
365 "mail.gmx.net",
366 vec![
367 IpAddr::V4(Ipv4Addr::new(212, 227, 17, 190)),
368 IpAddr::V4(Ipv4Addr::new(212, 227, 17, 168)),
369 ],
370 ),
371 (
372 "imap.gmx.net",
373 vec![
374 IpAddr::V4(Ipv4Addr::new(212, 227, 17, 170)),
375 IpAddr::V4(Ipv4Addr::new(212, 227, 17, 186)),
376 ],
377 ),
378 (
379 "mail.sangham.net",
380 vec![
381 IpAddr::V4(Ipv4Addr::new(159, 69, 186, 85)),
382 IpAddr::V6(Ipv6Addr::new(0x2a01, 0x4f8, 0xc17, 0x798c, 0, 0, 0, 1)),
383 ],
384 ),
385 (
386 "imap.mail.de",
387 vec![IpAddr::V4(Ipv4Addr::new(62, 201, 172, 16))],
388 ),
389 (
390 "smtp.mailbox.org",
391 vec![IpAddr::V4(Ipv4Addr::new(185, 97, 174, 196))],
392 ),
393 (
394 "imap.mailbox.org",
395 vec![IpAddr::V4(Ipv4Addr::new(185, 97, 174, 199))],
396 ),
397 (
398 "imap.naver.com",
399 vec![IpAddr::V4(Ipv4Addr::new(125, 209, 233, 34))],
400 ),
401 (
402 "imap.ouvaton.coop",
403 vec![IpAddr::V4(Ipv4Addr::new(194, 36, 166, 20))],
404 ),
405 (
406 "imap.purelymail.com",
407 vec![IpAddr::V4(Ipv4Addr::new(18, 204, 123, 63))],
408 ),
409 (
410 "mail.systemausfall.org",
411 vec![
412 IpAddr::V4(Ipv4Addr::new(51, 75, 71, 249)),
413 IpAddr::V4(Ipv4Addr::new(80, 153, 252, 42)),
414 ],
415 ),
416 (
417 "mail.systemli.org",
418 vec![IpAddr::V4(Ipv4Addr::new(93, 190, 126, 36))],
419 ),
420 ("testrun.org", vec![IpAddr::V4(Ipv4Addr::new(5, 1, 76, 52))]),
421 (
422 "nine.testrun.org",
423 vec![
424 IpAddr::V4(Ipv4Addr::new(128, 140, 126, 197)),
425 IpAddr::V4(Ipv4Addr::new(116, 202, 233, 236)),
426 IpAddr::V4(Ipv4Addr::new(216, 144, 228, 100)),
427 IpAddr::V6(Ipv6Addr::new(0x2a01, 0x4f8, 0x241, 0x4ce8, 0, 0, 0, 2)),
428 IpAddr::V6(Ipv6Addr::new(
429 0x2001, 0x41d0, 0x701, 0x1100, 0, 0, 0, 0x8ab1,
430 )),
431 ],
432 ),
433 (
434 "secureimap.t-online.de",
435 vec![
436 IpAddr::V4(Ipv4Addr::new(194, 25, 134, 114)),
437 IpAddr::V4(Ipv4Addr::new(194, 25, 134, 115)),
438 IpAddr::V4(Ipv4Addr::new(194, 25, 134, 50)),
439 IpAddr::V4(Ipv4Addr::new(194, 25, 134, 51)),
440 ],
441 ),
442 (
443 "securesmtp.t-online.de",
444 vec![
445 IpAddr::V4(Ipv4Addr::new(194, 25, 134, 46)),
446 IpAddr::V4(Ipv4Addr::new(194, 25, 134, 110)),
447 ],
448 ),
449 (
450 "mail.riseup.net",
451 vec![
452 IpAddr::V4(Ipv4Addr::new(198, 252, 153, 171)),
453 IpAddr::V4(Ipv4Addr::new(198, 252, 153, 170)),
454 ],
455 ),
456 (
457 "pimap.schulon.org",
458 vec![IpAddr::V4(Ipv4Addr::new(194, 77, 246, 20))],
459 ),
460 (
461 "imap.tiscali.it",
462 vec![IpAddr::V4(Ipv4Addr::new(213, 205, 33, 10))],
463 ),
464 (
465 "smtp.tiscali.it",
466 vec![IpAddr::V4(Ipv4Addr::new(213, 205, 33, 13))],
467 ),
468 (
469 "imap.ukr.net",
470 vec![IpAddr::V4(Ipv4Addr::new(212, 42, 75, 240))],
471 ),
472 (
473 "smtp.ukr.net",
474 vec![IpAddr::V4(Ipv4Addr::new(212, 42, 75, 250))],
475 ),
476 (
477 "imap.web.de",
478 vec![
479 IpAddr::V4(Ipv4Addr::new(212, 227, 17, 162)),
480 IpAddr::V4(Ipv4Addr::new(212, 227, 17, 178)),
481 ],
482 ),
483 (
484 "imap.ziggo.nl",
485 vec![IpAddr::V4(Ipv4Addr::new(84, 116, 6, 3))],
486 ),
487 (
488 "imap.zoho.eu",
489 vec![
490 IpAddr::V4(Ipv4Addr::new(185, 230, 214, 25)),
491 IpAddr::V4(Ipv4Addr::new(185, 230, 214, 206)),
492 ],
493 ),
494 (
495 "mail.infomaniak.com",
496 vec![
497 IpAddr::V4(Ipv4Addr::new(83, 166, 143, 44)),
498 IpAddr::V4(Ipv4Addr::new(83, 166, 143, 45)),
499 ],
500 ),
501 (
502 "mail.mymagenta.at",
503 vec![IpAddr::V4(Ipv4Addr::new(80, 109, 253, 241))],
504 ),
505 (
506 "mail.nubo.coop",
507 vec![IpAddr::V4(Ipv4Addr::new(79, 99, 201, 10))],
508 ),
509 (
510 "mx.freenet.de",
511 vec![
512 IpAddr::V4(Ipv4Addr::new(194, 97, 208, 36)),
513 IpAddr::V4(Ipv4Addr::new(194, 97, 208, 34)),
514 IpAddr::V4(Ipv4Addr::new(194, 97, 208, 35)),
515 IpAddr::V4(Ipv4Addr::new(194, 97, 208, 39)),
516 IpAddr::V4(Ipv4Addr::new(194, 97, 208, 37)),
517 IpAddr::V4(Ipv4Addr::new(194, 97, 208, 38)),
518 ],
519 ),
520 (
521 "posteo.de",
522 vec![
523 IpAddr::V4(Ipv4Addr::new(185, 67, 36, 168)),
524 IpAddr::V4(Ipv4Addr::new(185, 67, 36, 169)),
525 ],
526 ),
527 (
528 "psmtp.schulon.org",
529 vec![IpAddr::V4(Ipv4Addr::new(194, 77, 246, 20))],
530 ),
531 (
532 "smtp.mail.de",
533 vec![IpAddr::V4(Ipv4Addr::new(62, 201, 172, 21))],
534 ),
535 (
536 "smtp.mail.ru",
537 vec![
538 IpAddr::V4(Ipv4Addr::new(94, 100, 180, 160)),
539 IpAddr::V4(Ipv4Addr::new(217, 69, 139, 160)),
540 ],
541 ),
542 (
543 "imap.mail.yahoo.com",
544 vec![
545 IpAddr::V4(Ipv4Addr::new(87, 248, 103, 8)),
546 IpAddr::V4(Ipv4Addr::new(212, 82, 101, 24)),
547 ],
548 ),
549 (
550 "smtp.mail.yahoo.com",
551 vec![IpAddr::V4(Ipv4Addr::new(87, 248, 97, 36))],
552 ),
553 (
554 "imap.mailo.com",
555 vec![IpAddr::V4(Ipv4Addr::new(213, 182, 54, 20))],
556 ),
557 (
558 "imap.migadu.com",
559 vec![
560 IpAddr::V4(Ipv4Addr::new(51, 210, 3, 23)),
561 IpAddr::V4(Ipv4Addr::new(51, 210, 3, 20)),
562 ],
563 ),
564 (
565 "smtp.migadu.com",
566 vec![
567 IpAddr::V4(Ipv4Addr::new(37, 59, 57, 117)),
568 IpAddr::V4(Ipv4Addr::new(51, 255, 82, 75)),
569 ],
570 ),
571 (
572 "smtp.mailo.com",
573 vec![IpAddr::V4(Ipv4Addr::new(213, 182, 54, 20))],
574 ),
575 (
576 "smtp.naver.com",
577 vec![IpAddr::V4(Ipv4Addr::new(125, 209, 238, 155))],
578 ),
579 (
580 "smtp.ouvaton.coop",
581 vec![IpAddr::V4(Ipv4Addr::new(194, 36, 166, 20))],
582 ),
583 (
584 "smtp.purelymail.com",
585 vec![IpAddr::V4(Ipv4Addr::new(18, 204, 123, 63))],
586 ),
587 (
588 "imap.qq.com",
589 vec![
590 IpAddr::V4(Ipv4Addr::new(43, 163, 178, 76)),
591 IpAddr::V4(Ipv4Addr::new(43, 129, 255, 54)),
592 ],
593 ),
594 (
595 "smtp.qq.com",
596 vec![
597 IpAddr::V4(Ipv4Addr::new(43, 129, 255, 54)),
598 IpAddr::V4(Ipv4Addr::new(43, 163, 178, 76)),
599 ],
600 ),
601 (
602 "imap.rambler.ru",
603 vec![
604 IpAddr::V4(Ipv4Addr::new(81, 19, 77, 168)),
605 IpAddr::V4(Ipv4Addr::new(81, 19, 77, 169)),
606 IpAddr::V4(Ipv4Addr::new(81, 19, 77, 170)),
607 IpAddr::V4(Ipv4Addr::new(81, 19, 77, 171)),
608 ],
609 ),
610 (
611 "smtp.rambler.ru",
612 vec![
613 IpAddr::V4(Ipv4Addr::new(81, 19, 77, 164)),
614 IpAddr::V4(Ipv4Addr::new(81, 19, 77, 165)),
615 IpAddr::V4(Ipv4Addr::new(81, 19, 77, 166)),
616 IpAddr::V4(Ipv4Addr::new(81, 19, 77, 167)),
617 ],
618 ),
619 (
620 "stinpriza.net",
621 vec![IpAddr::V4(Ipv4Addr::new(5, 9, 122, 184))],
622 ),
623 (
624 "webbox222.server-home.org",
625 vec![IpAddr::V4(Ipv4Addr::new(91, 203, 111, 88))],
626 ),
627 (
628 "undernet.uy",
629 vec![IpAddr::V4(Ipv4Addr::new(200, 40, 115, 74))],
630 ),
631 (
632 "imap.vivaldi.net",
633 vec![IpAddr::V4(Ipv4Addr::new(31, 209, 137, 15))],
634 ),
635 (
636 "smtp.vivaldi.net",
637 vec![IpAddr::V4(Ipv4Addr::new(31, 209, 137, 12))],
638 ),
639 (
640 "imap.vodafonemail.de",
641 vec![
642 IpAddr::V4(Ipv4Addr::new(178, 15, 69, 210)),
643 IpAddr::V4(Ipv4Addr::new(151, 189, 176, 206)),
644 ],
645 ),
646 (
647 "smtp.vodafonemail.de",
648 vec![
649 IpAddr::V4(Ipv4Addr::new(151, 189, 176, 206)),
650 IpAddr::V4(Ipv4Addr::new(178, 15, 69, 206)),
651 ],
652 ),
653 (
654 "smtp.web.de",
655 vec![
656 IpAddr::V4(Ipv4Addr::new(213, 165, 67, 124)),
657 IpAddr::V4(Ipv4Addr::new(213, 165, 67, 108)),
658 ],
659 ),
660 (
661 "imap.yandex.com",
662 vec![IpAddr::V4(Ipv4Addr::new(77, 88, 21, 125))],
663 ),
664 (
665 "smtp.yandex.com",
666 vec![IpAddr::V4(Ipv4Addr::new(77, 88, 21, 158))],
667 ),
668 (
669 "smtp.ziggo.nl",
670 vec![IpAddr::V4(Ipv4Addr::new(84, 116, 6, 3))],
671 ),
672 (
673 "smtp.zoho.eu",
674 vec![
675 IpAddr::V4(Ipv4Addr::new(185, 230, 212, 164)),
676 IpAddr::V4(Ipv4Addr::new(185, 230, 214, 164)),
677 ],
678 ),
679 (
681 "mehl.cloud",
682 vec![IpAddr::V4(Ipv4Addr::new(95, 217, 223, 172))],
683 ),
684 (
685 "mailchat.pl",
686 vec![IpAddr::V4(Ipv4Addr::new(46, 62, 144, 137))],
687 ),
688 (
689 "chatmail.woodpeckersnest.space",
690 vec![IpAddr::V4(Ipv4Addr::new(85, 215, 162, 146))],
691 ),
692 (
693 "chatmail.culturanerd.it",
694 vec![IpAddr::V4(Ipv4Addr::new(82, 165, 94, 165))],
695 ),
696 (
697 "chatmail.hackea.org",
698 vec![IpAddr::V4(Ipv4Addr::new(82, 165, 11, 85))],
699 ),
700 (
701 "chika.aangat.lahat.computer",
702 vec![IpAddr::V4(Ipv4Addr::new(71, 19, 150, 113))],
703 ),
704 (
705 "tarpit.fun",
706 vec![IpAddr::V4(Ipv4Addr::new(152, 53, 86, 246))],
707 ),
708 (
709 "d.gaufr.es",
710 vec![IpAddr::V4(Ipv4Addr::new(51, 77, 140, 91))],
711 ),
712 (
713 "chtml.ca",
714 vec![IpAddr::V4(Ipv4Addr::new(51, 222, 156, 177))],
715 ),
716 (
717 "chatmail.au",
718 vec![IpAddr::V4(Ipv4Addr::new(45, 124, 54, 79))],
719 ),
720 (
721 "sombras.chat",
722 vec![IpAddr::V4(Ipv4Addr::new(82, 25, 70, 154))],
723 ),
724 (
725 "e2ee.wang",
726 vec![IpAddr::V4(Ipv4Addr::new(139, 84, 233, 161))],
727 ),
728 (
729 "chat.privittytech.com",
730 vec![IpAddr::V4(Ipv4Addr::new(35, 154, 144, 0))],
731 ),
732 ("e2ee.im", vec![IpAddr::V4(Ipv4Addr::new(45, 137, 99, 57))]),
733 (
734 "chatmail.email",
735 vec![IpAddr::V4(Ipv4Addr::new(57, 128, 220, 120))],
736 ),
737 (
738 "danneskjold.de",
739 vec![IpAddr::V4(Ipv4Addr::new(46, 62, 216, 132))],
740 ),
741 (
742 "darkrun.dev",
743 vec![IpAddr::V4(Ipv4Addr::new(72, 11, 149, 146))],
744 ),
745 ])
746});
747
748async fn lookup_cache(
749 context: &Context,
750 host: &str,
751 port: u16,
752 alpn: &str,
753 now: i64,
754) -> Result<Vec<SocketAddr>> {
755 let mut res = Vec::new();
756 for cached_address in context
757 .sql
758 .query_map_vec(
759 "SELECT dns_cache.address
760 FROM dns_cache
761 LEFT JOIN connection_history
762 ON dns_cache.hostname = connection_history.host
763 AND dns_cache.address = connection_history.addr
764 AND connection_history.port = ?
765 AND connection_history.alpn = ?
766 WHERE dns_cache.hostname = ?
767 AND ? < dns_cache.timestamp + ?
768 ORDER BY IFNULL(connection_history.timestamp, dns_cache.timestamp) DESC
769 LIMIT 50",
770 (port, alpn, host, now, super::CACHE_TTL),
771 |row| {
772 let address: String = row.get(0)?;
773 Ok(address)
774 },
775 )
776 .await?
777 {
778 match IpAddr::from_str(&cached_address) {
779 Ok(ip_addr) => {
780 let addr = SocketAddr::new(ip_addr, port);
781 res.push(addr);
782 }
783 Err(err) => {
784 warn!(
785 context,
786 "Failed to parse cached address {:?}: {:#}.", cached_address, err
787 );
788 }
789 }
790 }
791 Ok(res)
792}
793
794async fn sort_by_connection_timestamp(
797 context: &Context,
798 input: Vec<SocketAddr>,
799 alpn: &str,
800 host: &str,
801) -> Result<Vec<SocketAddr>> {
802 let mut res: Vec<(Option<i64>, SocketAddr)> = Vec::with_capacity(input.len());
803 for addr in input {
804 let timestamp = load_connection_timestamp(
805 &context.sql,
806 alpn,
807 host,
808 addr.port(),
809 Some(&addr.ip().to_string()),
810 )
811 .await?;
812 res.push((timestamp, addr));
813 }
814 res.sort_by_key(|(ts, _addr)| std::cmp::Reverse(*ts));
815 Ok(res.into_iter().map(|(_ts, addr)| addr).collect())
816}
817
818pub(crate) async fn lookup_host_with_cache(
829 context: &Context,
830 hostname: &str,
831 port: u16,
832 alpn: &str,
833 load_cache: bool,
834) -> Result<Vec<SocketAddr>> {
835 let now = time();
836 let resolved_addrs = match lookup_host_and_update_cache(context, hostname, port, now).await {
837 Ok(res) => {
838 if alpn.is_empty() {
839 res
840 } else {
841 sort_by_connection_timestamp(context, res, alpn, hostname).await?
842 }
843 }
844 Err(err) => {
845 warn!(
846 context,
847 "DNS resolution for {hostname}:{port} failed: {err:#}."
848 );
849 Vec::new()
850 }
851 };
852
853 if load_cache {
854 let mut cache = lookup_cache(context, hostname, port, alpn, now).await?;
855 if let Some(ips) = DNS_PRELOAD.get(hostname) {
856 for ip in ips {
857 let addr = SocketAddr::new(*ip, port);
858 if !cache.contains(&addr) {
859 cache.push(addr);
860 }
861 }
862 }
863
864 Ok(merge_with_cache(resolved_addrs, cache))
865 } else {
866 Ok(resolved_addrs)
867 }
868}
869
870fn merge_with_cache(
874 mut resolved_addrs: Vec<SocketAddr>,
875 cache: Vec<SocketAddr>,
876) -> Vec<SocketAddr> {
877 let rest = resolved_addrs.split_off(std::cmp::min(resolved_addrs.len(), 2));
878
879 for addr in cache.into_iter().chain(rest.into_iter()) {
880 if !resolved_addrs.contains(&addr) {
881 resolved_addrs.push(addr);
882 if resolved_addrs.len() >= 10 {
883 break;
884 }
885 }
886 }
887
888 resolved_addrs
889}
890
891#[cfg(test)]
892mod tests {
893 use super::*;
894
895 use crate::net::update_connection_history;
896 use crate::test_utils::TestContext;
897
898 #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
899 async fn test_sort_by_connection_timestamp() {
900 let alice = &TestContext::new_alice().await;
901 let now = time();
902
903 let ipv6_addr = IpAddr::V6(Ipv6Addr::new(0x2a01, 0x4f8, 0x241, 0x4ce8, 0, 0, 0, 2));
904 let ipv4_addr = IpAddr::V4(Ipv4Addr::new(116, 202, 233, 236));
905
906 assert_eq!(
907 sort_by_connection_timestamp(
908 alice,
909 vec![
910 SocketAddr::new(ipv6_addr, 993),
911 SocketAddr::new(ipv4_addr, 993)
912 ],
913 "imap",
914 "nine.testrun.org"
915 )
916 .await
917 .unwrap(),
918 vec![
919 SocketAddr::new(ipv6_addr, 993),
920 SocketAddr::new(ipv4_addr, 993)
921 ]
922 );
923 update_connection_history(
924 alice,
925 "imap",
926 "nine.testrun.org",
927 993,
928 "116.202.233.236",
929 now,
930 )
931 .await
932 .unwrap();
933 assert_eq!(
934 sort_by_connection_timestamp(
935 alice,
936 vec![
937 SocketAddr::new(ipv6_addr, 993),
938 SocketAddr::new(ipv4_addr, 993)
939 ],
940 "imap",
941 "nine.testrun.org"
942 )
943 .await
944 .unwrap(),
945 vec![
946 SocketAddr::new(ipv4_addr, 993),
947 SocketAddr::new(ipv6_addr, 993),
948 ]
949 );
950
951 assert_eq!(
952 sort_by_connection_timestamp(
953 alice,
954 vec![
955 SocketAddr::new(ipv6_addr, 465),
956 SocketAddr::new(ipv4_addr, 465)
957 ],
958 "smtp",
959 "nine.testrun.org"
960 )
961 .await
962 .unwrap(),
963 vec![
964 SocketAddr::new(ipv6_addr, 465),
965 SocketAddr::new(ipv4_addr, 465),
966 ]
967 );
968 update_connection_history(
969 alice,
970 "smtp",
971 "nine.testrun.org",
972 465,
973 "116.202.233.236",
974 now,
975 )
976 .await
977 .unwrap();
978 assert_eq!(
979 sort_by_connection_timestamp(
980 alice,
981 vec![
982 SocketAddr::new(ipv6_addr, 465),
983 SocketAddr::new(ipv4_addr, 465)
984 ],
985 "smtp",
986 "nine.testrun.org"
987 )
988 .await
989 .unwrap(),
990 vec![
991 SocketAddr::new(ipv4_addr, 465),
992 SocketAddr::new(ipv6_addr, 465),
993 ]
994 );
995
996 update_connection_history(
997 alice,
998 "imap",
999 "nine.testrun.org",
1000 993,
1001 "2a01:4f8:241:4ce8::2",
1002 now,
1003 )
1004 .await
1005 .unwrap();
1006 assert_eq!(
1007 sort_by_connection_timestamp(
1008 alice,
1009 vec![
1010 SocketAddr::new(ipv6_addr, 993),
1011 SocketAddr::new(ipv4_addr, 993)
1012 ],
1013 "imap",
1014 "nine.testrun.org"
1015 )
1016 .await
1017 .unwrap(),
1018 vec![
1019 SocketAddr::new(ipv6_addr, 993),
1020 SocketAddr::new(ipv4_addr, 993)
1021 ]
1022 );
1023 }
1024
1025 #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
1026 async fn test_lookup_cache() {
1027 let alice = &TestContext::new_alice().await;
1028
1029 let ipv4_addr = IpAddr::V4(Ipv4Addr::new(116, 202, 233, 236));
1030 let ipv6_addr = IpAddr::V6(Ipv6Addr::new(0x2a01, 0x4f8, 0x241, 0x4ce8, 0, 0, 0, 2));
1031
1032 let now = time();
1033 assert!(
1034 lookup_cache(alice, "nine.testrun.org", 587, "smtp", now)
1035 .await
1036 .unwrap()
1037 .is_empty()
1038 );
1039
1040 update_cache(alice, "nine.testrun.org", "116.202.233.236", now)
1041 .await
1042 .unwrap();
1043
1044 assert_eq!(
1045 lookup_cache(alice, "nine.testrun.org", 587, "smtp", now)
1046 .await
1047 .unwrap(),
1048 vec![SocketAddr::new(ipv4_addr, 587)]
1049 );
1050
1051 assert_eq!(
1054 lookup_cache(alice, "nine.testrun.org", 443, "", now)
1055 .await
1056 .unwrap(),
1057 vec![SocketAddr::new(ipv4_addr, 443)]
1058 );
1059
1060 update_cache(alice, "nine.testrun.org", "2a01:4f8:241:4ce8::2", now + 30)
1061 .await
1062 .unwrap();
1063
1064 assert_eq!(
1066 lookup_cache(alice, "nine.testrun.org", 443, "", now + 60)
1067 .await
1068 .unwrap(),
1069 vec![
1070 SocketAddr::new(ipv6_addr, 443),
1071 SocketAddr::new(ipv4_addr, 443)
1072 ],
1073 );
1074
1075 update_connection_history(
1078 alice,
1079 "smtp",
1080 "nine.testrun.org",
1081 465,
1082 "116.202.233.236",
1083 now + 100,
1084 )
1085 .await
1086 .unwrap();
1087 assert_eq!(
1088 lookup_cache(alice, "nine.testrun.org", 465, "smtp", now + 120)
1089 .await
1090 .unwrap(),
1091 vec![
1092 SocketAddr::new(ipv4_addr, 465),
1093 SocketAddr::new(ipv6_addr, 465)
1094 ]
1095 );
1096
1097 assert_eq!(
1099 lookup_cache(alice, "nine.testrun.org", 993, "imap", now + 120)
1100 .await
1101 .unwrap(),
1102 vec![
1103 SocketAddr::new(ipv6_addr, 993),
1104 SocketAddr::new(ipv4_addr, 993)
1105 ],
1106 );
1107 assert_eq!(
1108 lookup_cache(alice, "nine.testrun.org", 465, "imap", now + 120)
1109 .await
1110 .unwrap(),
1111 vec![
1112 SocketAddr::new(ipv6_addr, 465),
1113 SocketAddr::new(ipv4_addr, 465)
1114 ],
1115 );
1116 assert_eq!(
1117 lookup_cache(alice, "nine.testrun.org", 993, "smtp", now + 120)
1118 .await
1119 .unwrap(),
1120 vec![
1121 SocketAddr::new(ipv6_addr, 993),
1122 SocketAddr::new(ipv4_addr, 993)
1123 ],
1124 );
1125 }
1126
1127 #[test]
1128 fn test_merge_with_cache() {
1129 let first_addr = IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1));
1130 let second_addr = IpAddr::V4(Ipv4Addr::new(192, 168, 1, 2));
1131
1132 {
1134 let resolved_addrs = vec![
1135 SocketAddr::new(first_addr, 993),
1136 SocketAddr::new(second_addr, 993),
1137 ];
1138 let cache = vec![];
1139 assert_eq!(
1140 merge_with_cache(resolved_addrs.clone(), cache),
1141 resolved_addrs
1142 );
1143 }
1144
1145 {
1148 let resolved_addrs = vec![SocketAddr::new(first_addr, 993)];
1149 let cache = vec![SocketAddr::new(second_addr, 993)];
1150 assert_eq!(
1151 merge_with_cache(resolved_addrs, cache),
1152 vec![
1153 SocketAddr::new(first_addr, 993),
1154 SocketAddr::new(second_addr, 993),
1155 ]
1156 );
1157 }
1158
1159 {
1162 let resolved_addrs = vec![
1163 SocketAddr::new(first_addr, 993),
1164 SocketAddr::new(second_addr, 993),
1165 ];
1166 let cache = vec![SocketAddr::new(second_addr, 993)];
1167 assert_eq!(
1168 merge_with_cache(resolved_addrs, cache),
1169 vec![
1170 SocketAddr::new(first_addr, 993),
1171 SocketAddr::new(second_addr, 993),
1172 ]
1173 );
1174 }
1175
1176 {
1180 let resolved_addrs = vec![
1181 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 993),
1182 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 2)), 993),
1183 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 3)), 993),
1184 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 4)), 993),
1185 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 5)), 993),
1186 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 6)), 993),
1187 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 7)), 993),
1188 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 8)), 993),
1189 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 9)), 993),
1190 ];
1191 let cache = vec![SocketAddr::new(second_addr, 993)];
1192 assert_eq!(
1193 merge_with_cache(resolved_addrs, cache),
1194 vec![
1195 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 993),
1196 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 2)), 993),
1197 SocketAddr::new(second_addr, 993),
1198 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 3)), 993),
1199 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 4)), 993),
1200 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 5)), 993),
1201 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 6)), 993),
1202 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 7)), 993),
1203 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 8)), 993),
1204 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 9)), 993),
1205 ]
1206 );
1207 }
1208
1209 {
1214 let resolved_addrs = vec![
1215 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 993),
1216 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 2)), 993),
1217 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 3)), 993),
1218 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 4)), 993),
1219 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 5)), 993),
1220 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 6)), 993),
1221 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 7)), 993),
1222 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 8)), 993),
1223 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 9)), 993),
1224 ];
1225 let cache = vec![
1226 SocketAddr::new(second_addr, 993),
1227 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 9)), 993),
1228 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 8)), 993),
1229 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 7)), 993),
1230 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 6)), 993),
1231 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 5)), 993),
1232 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 4)), 993),
1233 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 3)), 993),
1234 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 2)), 993),
1235 ];
1236 assert_eq!(
1237 merge_with_cache(resolved_addrs, cache),
1238 vec![
1239 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 993),
1240 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 2)), 993),
1241 SocketAddr::new(second_addr, 993),
1242 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 9)), 993),
1243 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 8)), 993),
1244 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 7)), 993),
1245 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 6)), 993),
1246 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 5)), 993),
1247 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 4)), 993),
1248 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 3)), 993),
1249 ]
1250 );
1251 }
1252 }
1253}