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