hosts.rs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. use async_std::sync::{Arc, Mutex};
  2. use std::net::IpAddr;
  3. use fxhash::FxHashSet;
  4. use ipnet::{Ipv4Net, Ipv6Net};
  5. use iprange::IpRange;
  6. use url::Url;
  7. use super::constants::{IP4_PRIV_RANGES, IP6_PRIV_RANGES, LOCALNET};
  8. /// Pointer to hosts class.
  9. pub type HostsPtr = Arc<Hosts>;
  10. /// Manages a store of network addresses.
  11. pub struct Hosts {
  12. addrs: Mutex<FxHashSet<Url>>,
  13. localnet: bool,
  14. ipv4_range: IpRange<Ipv4Net>,
  15. ipv6_range: IpRange<Ipv6Net>,
  16. }
  17. impl Hosts {
  18. /// Create a new host list.
  19. pub fn new(localnet: bool) -> Arc<Self> {
  20. // Initialize ipv4_range and ipv6_range if needed
  21. let mut ipv4_range: IpRange<Ipv4Net> =
  22. IP4_PRIV_RANGES.iter().map(|s| s.parse().unwrap()).collect();
  23. let mut ipv6_range: IpRange<Ipv6Net> =
  24. IP6_PRIV_RANGES.iter().map(|s| s.parse().unwrap()).collect();
  25. // These will make the trie potentially smaller
  26. ipv4_range.simplify();
  27. ipv6_range.simplify();
  28. Arc::new(Self { addrs: Mutex::new(FxHashSet::default()), localnet, ipv4_range, ipv6_range })
  29. }
  30. /// Add a new host to the host list, after filtering.
  31. pub async fn store(&self, input_addrs: Vec<Url>) {
  32. let addrs = if !self.localnet {
  33. let filtered = filter_localnet(input_addrs);
  34. filter_invalid(&self.ipv4_range, &self.ipv6_range, filtered)
  35. } else {
  36. input_addrs
  37. };
  38. let mut addrs_map = self.addrs.lock().await;
  39. for addr in addrs {
  40. addrs_map.insert(addr);
  41. }
  42. }
  43. /// Add a new hosts external adders to the host list, after filtering and verifying
  44. /// the address url resolves to the provided connection address.
  45. pub async fn store_ext(&self, connection_addr: Url, input_addrs: Vec<Url>) {
  46. let addrs = if !self.localnet {
  47. let filtered = filter_localnet(input_addrs);
  48. let filtered = filter_invalid(&self.ipv4_range, &self.ipv6_range, filtered);
  49. filter_non_resolving(connection_addr, filtered)
  50. } else {
  51. input_addrs
  52. };
  53. let mut addrs_map = self.addrs.lock().await;
  54. for addr in addrs {
  55. addrs_map.insert(addr);
  56. }
  57. }
  58. /// Return the list of hosts.
  59. pub async fn load_all(&self) -> Vec<Url> {
  60. self.addrs.lock().await.iter().cloned().collect()
  61. }
  62. /// Remove an Url from the list
  63. pub async fn remove(&self, url: &Url) -> bool {
  64. self.addrs.lock().await.remove(url)
  65. }
  66. /// Check if the host list is empty.
  67. pub async fn is_empty(&self) -> bool {
  68. self.addrs.lock().await.is_empty()
  69. }
  70. }
  71. /// Auxiliary function to filter localnet hosts.
  72. fn filter_localnet(input_addrs: Vec<Url>) -> Vec<Url> {
  73. let mut filtered = vec![];
  74. for addr in &input_addrs {
  75. match addr.host_str() {
  76. Some(host_str) => {
  77. if LOCALNET.contains(&host_str) {
  78. continue
  79. }
  80. }
  81. None => continue,
  82. }
  83. filtered.push(addr.clone());
  84. }
  85. filtered
  86. }
  87. /// Auxiliary function to filter invalid(unresolvable) hosts.
  88. fn filter_invalid(
  89. ipv4_range: &IpRange<Ipv4Net>,
  90. ipv6_range: &IpRange<Ipv6Net>,
  91. input_addrs: Vec<Url>,
  92. ) -> Vec<Url> {
  93. let mut filtered = vec![];
  94. for addr in &input_addrs {
  95. // Discard domainless Urls
  96. let domain = match addr.domain() {
  97. Some(d) => d,
  98. None => continue,
  99. };
  100. // Validate onion domain
  101. if domain.ends_with(".onion") && is_valid_onion(domain) {
  102. filtered.push(addr.clone());
  103. continue
  104. }
  105. // Validate normal domain
  106. if let Ok(socket_addrs) = addr.socket_addrs(|| None) {
  107. // Check if domain resolved to anything
  108. if socket_addrs.is_empty() {
  109. continue
  110. }
  111. // Checking resolved IP validity
  112. let mut valid = true;
  113. for i in socket_addrs {
  114. match i.ip() {
  115. IpAddr::V4(a) => {
  116. if ipv4_range.contains(&a) {
  117. valid = false;
  118. break
  119. }
  120. }
  121. IpAddr::V6(a) => {
  122. if ipv6_range.contains(&a) {
  123. valid = false;
  124. break
  125. }
  126. }
  127. }
  128. }
  129. if valid {
  130. filtered.push(addr.clone());
  131. }
  132. }
  133. }
  134. filtered
  135. }
  136. /// Auxiliary function to filter unresolvable hosts, based on provided connection addr (excluding onion).
  137. fn filter_non_resolving(connection_addr: Url, input_addrs: Vec<Url>) -> Vec<Url> {
  138. let connection_domain = connection_addr.domain().unwrap();
  139. // Validate connection onion domain
  140. if connection_domain.ends_with(".onion") && !is_valid_onion(connection_domain) {
  141. return vec![]
  142. }
  143. // Retrieve connection IPs
  144. let mut ipv4_range = vec![];
  145. let mut ipv6_range = vec![];
  146. for i in connection_addr.socket_addrs(|| None).unwrap() {
  147. match i.ip() {
  148. IpAddr::V4(a) => {
  149. ipv4_range.push(a);
  150. }
  151. IpAddr::V6(a) => {
  152. ipv6_range.push(a);
  153. }
  154. }
  155. }
  156. // Filter input addresses
  157. let mut filtered = vec![];
  158. for addr in input_addrs {
  159. // Keep valid onion domains
  160. let addr_domain = addr.domain().unwrap();
  161. if addr_domain.ends_with(".onion") && addr_domain == connection_domain {
  162. filtered.push(addr.clone());
  163. continue
  164. }
  165. // Checking IP validity
  166. let mut valid = true;
  167. let socket_addrs = addr.socket_addrs(|| None).unwrap();
  168. for i in socket_addrs {
  169. match i.ip() {
  170. IpAddr::V4(a) => {
  171. if !ipv4_range.contains(&a) {
  172. valid = false;
  173. break
  174. }
  175. }
  176. IpAddr::V6(a) => {
  177. if !ipv6_range.contains(&a) {
  178. valid = false;
  179. break
  180. }
  181. }
  182. }
  183. }
  184. if valid {
  185. filtered.push(addr.clone());
  186. }
  187. }
  188. filtered
  189. }
  190. /// Auxiliary function to validate an onion.
  191. fn is_valid_onion(onion: &str) -> bool {
  192. let onion = match onion.strip_suffix(".onion") {
  193. Some(s) => s,
  194. None => onion,
  195. };
  196. if onion.len() != 56 {
  197. return false
  198. }
  199. let alphabet = base32::Alphabet::RFC4648 { padding: false };
  200. base32::decode(alphabet, onion).is_some()
  201. }