hosts.rs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  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. for addr in addrs {
  39. self.addrs.lock().await.insert(addr);
  40. }
  41. }
  42. /// Add a new hosts external adders to the host list, after filtering and verifying
  43. /// the address url resolves to the provided connection address.
  44. pub async fn store_ext(&self, connection_addr: Url, input_addrs: Vec<Url>) {
  45. let addrs = if !self.localnet {
  46. let filtered = filter_localnet(input_addrs);
  47. let filtered = filter_invalid(&self.ipv4_range, &self.ipv6_range, filtered);
  48. filter_non_resolving(connection_addr, filtered)
  49. } else {
  50. input_addrs
  51. };
  52. for addr in addrs {
  53. self.addrs.lock().await.insert(addr);
  54. }
  55. }
  56. /// Return the list of hosts.
  57. pub async fn load_all(&self) -> Vec<Url> {
  58. self.addrs.lock().await.iter().cloned().collect()
  59. }
  60. /// Remove an Url from the list
  61. pub async fn remove(&self, url: &Url) -> bool {
  62. self.addrs.lock().await.remove(url)
  63. }
  64. /// Check if the host list is empty.
  65. pub async fn is_empty(&self) -> bool {
  66. self.addrs.lock().await.is_empty()
  67. }
  68. }
  69. /// Auxiliary function to filter localnet hosts.
  70. fn filter_localnet(input_addrs: Vec<Url>) -> Vec<Url> {
  71. let mut filtered = vec![];
  72. for addr in &input_addrs {
  73. match addr.host_str() {
  74. Some(host_str) => {
  75. if LOCALNET.contains(&host_str) {
  76. continue
  77. }
  78. }
  79. None => continue,
  80. }
  81. filtered.push(addr.clone());
  82. }
  83. filtered
  84. }
  85. /// Auxiliary function to filter invalid(unresolvable) hosts.
  86. fn filter_invalid(
  87. ipv4_range: &IpRange<Ipv4Net>,
  88. ipv6_range: &IpRange<Ipv6Net>,
  89. input_addrs: Vec<Url>,
  90. ) -> Vec<Url> {
  91. let mut filtered = vec![];
  92. for addr in &input_addrs {
  93. // Discard domainless Urls
  94. let domain = match addr.domain() {
  95. Some(d) => d,
  96. None => continue,
  97. };
  98. // Validate onion domain
  99. if domain.ends_with(".onion") && is_valid_onion(domain) {
  100. filtered.push(addr.clone());
  101. continue
  102. }
  103. // Validate normal domain
  104. if let Ok(socket_addrs) = addr.socket_addrs(|| None) {
  105. // Check if domain resolved to anything
  106. if socket_addrs.is_empty() {
  107. continue
  108. }
  109. // Checking resolved IP validity
  110. let mut valid = true;
  111. for i in socket_addrs {
  112. match i.ip() {
  113. IpAddr::V4(a) => {
  114. if ipv4_range.contains(&a) {
  115. valid = false;
  116. break
  117. }
  118. }
  119. IpAddr::V6(a) => {
  120. if ipv6_range.contains(&a) {
  121. valid = false;
  122. break
  123. }
  124. }
  125. }
  126. }
  127. if valid {
  128. filtered.push(addr.clone());
  129. }
  130. }
  131. }
  132. filtered
  133. }
  134. /// Auxiliary function to filter unresolvable hosts, based on provided connection addr (excluding onion).
  135. fn filter_non_resolving(connection_addr: Url, input_addrs: Vec<Url>) -> Vec<Url> {
  136. let connection_domain = connection_addr.domain().unwrap();
  137. // Validate connection onion domain
  138. if connection_domain.ends_with(".onion") && !is_valid_onion(connection_domain) {
  139. return vec![]
  140. }
  141. // Retrieve connection IPs
  142. let mut ipv4_range = vec![];
  143. let mut ipv6_range = vec![];
  144. for i in connection_addr.socket_addrs(|| None).unwrap() {
  145. match i.ip() {
  146. IpAddr::V4(a) => {
  147. ipv4_range.push(a);
  148. }
  149. IpAddr::V6(a) => {
  150. ipv6_range.push(a);
  151. }
  152. }
  153. }
  154. // Filter input addresses
  155. let mut filtered = vec![];
  156. for addr in input_addrs {
  157. // Keep valid onion domains
  158. let addr_domain = addr.domain().unwrap();
  159. if addr_domain.ends_with(".onion") && addr_domain == connection_domain {
  160. filtered.push(addr.clone());
  161. continue
  162. }
  163. // Checking IP validity
  164. let mut valid = true;
  165. let socket_addrs = addr.socket_addrs(|| None).unwrap();
  166. for i in socket_addrs {
  167. match i.ip() {
  168. IpAddr::V4(a) => {
  169. if !ipv4_range.contains(&a) {
  170. valid = false;
  171. break
  172. }
  173. }
  174. IpAddr::V6(a) => {
  175. if !ipv6_range.contains(&a) {
  176. valid = false;
  177. break
  178. }
  179. }
  180. }
  181. }
  182. if valid {
  183. filtered.push(addr.clone());
  184. }
  185. }
  186. filtered
  187. }
  188. /// Auxiliary function to validate an onion.
  189. fn is_valid_onion(onion: &str) -> bool {
  190. let onion = match onion.strip_suffix(".onion") {
  191. Some(s) => s,
  192. None => onion,
  193. };
  194. if onion.len() != 56 {
  195. return false
  196. }
  197. let alphabet = base32::Alphabet::RFC4648 { padding: false };
  198. base32::decode(alphabet, onion).is_some()
  199. }