xref: /aosp_15_r20/tools/netsim/rust/http-proxy/src/dns_manager.rs (revision cf78ab8cffb8fc9207af348f23af247fb04370a6)
1 // Copyright 2024 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 /// This module provides a reverse-dns function that caches the domain
16 /// name (FQDNs) and IpAddr from DNS answer records.
17 ///
18 /// This manager exists for two reasons:
19 ///
20 /// 1. RFC2817 Compliance (b/37055721): Requires converting IP address to
21 /// hostname for HTTP CONNECT requests.
22 ///
23 /// 2. Proxy bypass/exclusion list requires matching on host name
24 /// patterns.
25 ///
26 use crate::dns;
27 use etherparse::{PacketHeaders, PayloadSlice, TransportHeader};
28 use std::collections::HashMap;
29 use std::net::IpAddr;
30 
31 pub struct DnsManager {
32     map: HashMap<IpAddr, String>,
33 }
34 
35 impl DnsManager {
36     const DNS_PORT: u16 = 53;
37 
new() -> Self38     pub fn new() -> Self {
39         DnsManager { map: HashMap::new() }
40     }
41 
42     /// Add potential DNS entries to the cache.
add_from_packet_headers(&mut self, headers: &PacketHeaders)43     pub fn add_from_packet_headers(&mut self, headers: &PacketHeaders) {
44         // Check if the packet contains a UDP header
45         // with source port from DNS server
46         // and DNS answers with A/AAAA records
47         if let Some(TransportHeader::Udp(udp_header)) = &headers.transport {
48             // with source port from DNS server
49             if udp_header.source_port == Self::DNS_PORT {
50                 if let PayloadSlice::Udp(ref payload) = headers.payload {
51                     // Add any A/AAAA domain names
52                     if let Ok(answers) = dns::parse_answers(payload) {
53                         for (ip_addr, name) in answers {
54                             self.map.insert(ip_addr, name);
55                         }
56                     }
57                 }
58             }
59         }
60     }
61 
add_from_ethernet_slice(&mut self, packet: &[u8])62     pub fn add_from_ethernet_slice(&mut self, packet: &[u8]) {
63         let headers = PacketHeaders::from_ethernet_slice(packet).unwrap();
64         self.add_from_packet_headers(&headers);
65     }
66 
67     /// Return a FQDN from a prior DNS response for ip address
get(&self, ip_addr: &IpAddr) -> Option<String>68     pub fn get(&self, ip_addr: &IpAddr) -> Option<String> {
69         self.map.get(ip_addr).cloned()
70     }
71 
len(&self) -> usize72     pub fn len(&self) -> usize {
73         self.map.len()
74     }
75 }
76