summaryrefslogtreecommitdiffstats
path: root/third_party/rust/webrtc-sdp/src/anonymizer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/webrtc-sdp/src/anonymizer.rs')
-rw-r--r--third_party/rust/webrtc-sdp/src/anonymizer.rs198
1 files changed, 198 insertions, 0 deletions
diff --git a/third_party/rust/webrtc-sdp/src/anonymizer.rs b/third_party/rust/webrtc-sdp/src/anonymizer.rs
new file mode 100644
index 0000000000..a3d4d50aa7
--- /dev/null
+++ b/third_party/rust/webrtc-sdp/src/anonymizer.rs
@@ -0,0 +1,198 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+extern crate url;
+use address::{Address, ExplicitlyTypedAddress};
+use std::collections::HashMap;
+use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+use std::num::Wrapping;
+
+pub trait AnonymizingClone {
+ fn masked_clone(&self, anon: &mut StatefulSdpAnonymizer) -> Self;
+}
+
+pub trait ToBytesVec {
+ fn to_byte_vec(&self) -> Vec<u8>;
+}
+
+impl ToBytesVec for u64 {
+ fn to_byte_vec(&self) -> Vec<u8> {
+ let mut bytes = Vec::new();
+ let mut val = *self;
+ for _ in 0..8 {
+ bytes.push(val as u8);
+ val <<= 8;
+ }
+ bytes.reverse();
+ bytes
+ }
+}
+
+/*
+* Anonymizes SDP in a stateful fashion, such that a pre-anonymized value will
+* always be transformed into the same anonymized value within the context of
+* the anonymizer.
+* Stores the opaque state necessary for intelligent anonymization of SDP. This
+* state can be stored and reused during the offer-answer period, and it
+* will maintain a stable set of masked values.
+*/
+pub struct StatefulSdpAnonymizer {
+ ips: HashMap<IpAddr, IpAddr>,
+ ip_v4_inc: Wrapping<u32>,
+ ip_v6_inc: Wrapping<u128>,
+ host_names: AnonymizationStrMap,
+ ports: HashMap<u32, u32>,
+ port_inc: Wrapping<u32>,
+ origin_users: AnonymizationStrMap,
+ ice_passwords: AnonymizationStrMap,
+ ice_users: AnonymizationStrMap,
+ cert_finger_prints: HashMap<Vec<u8>, Vec<u8>>,
+ cert_finger_print_inc: Wrapping<u64>,
+ cnames: AnonymizationStrMap,
+}
+
+impl Default for StatefulSdpAnonymizer {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl StatefulSdpAnonymizer {
+ pub fn new() -> Self {
+ StatefulSdpAnonymizer {
+ ips: HashMap::new(),
+ ip_v4_inc: Wrapping(0),
+ ip_v6_inc: Wrapping(0),
+ host_names: AnonymizationStrMap::new("fqdn-", 8),
+ ports: HashMap::new(),
+ port_inc: Wrapping(0),
+ origin_users: AnonymizationStrMap::new("origin-user-", 8),
+ ice_passwords: AnonymizationStrMap::new("ice-password-", 8),
+ ice_users: AnonymizationStrMap::new("ice-user-", 8),
+ cert_finger_prints: HashMap::new(),
+ cert_finger_print_inc: Wrapping(0),
+ cnames: AnonymizationStrMap::new("cname-", 8),
+ }
+ }
+
+ pub fn mask_host(&mut self, host: &str) -> String {
+ self.host_names.mask(host)
+ }
+
+ pub fn mask_ip(&mut self, addr: &IpAddr) -> IpAddr {
+ if let Some(address) = self.ips.get(addr) {
+ return *address;
+ }
+ let mapped = match addr {
+ IpAddr::V4(_) => {
+ self.ip_v4_inc += Wrapping(1);
+ IpAddr::V4(Ipv4Addr::from(self.ip_v4_inc.0))
+ }
+ IpAddr::V6(_) => {
+ self.ip_v6_inc += Wrapping(1);
+ IpAddr::V6(Ipv6Addr::from(self.ip_v6_inc.0))
+ }
+ };
+ self.ips.insert(*addr, mapped);
+ mapped
+ }
+
+ pub fn mask_address(&mut self, address: &Address) -> Address {
+ match address {
+ Address::Fqdn(host) => Address::Fqdn(self.mask_host(host)),
+ Address::Ip(ip) => Address::Ip(self.mask_ip(ip)),
+ }
+ }
+
+ pub fn mask_typed_address(
+ &mut self,
+ address: &ExplicitlyTypedAddress,
+ ) -> ExplicitlyTypedAddress {
+ match address {
+ ExplicitlyTypedAddress::Fqdn {
+ address_type,
+ domain,
+ } => ExplicitlyTypedAddress::Fqdn {
+ address_type: *address_type,
+ domain: self.mask_host(domain),
+ },
+ ExplicitlyTypedAddress::Ip(ip) => ExplicitlyTypedAddress::Ip(self.mask_ip(ip)),
+ }
+ }
+
+ pub fn mask_port(&mut self, port: u32) -> u32 {
+ if let Some(stored) = self.ports.get(&port) {
+ return *stored;
+ }
+ self.port_inc += Wrapping(1);
+ self.ports.insert(port, self.port_inc.0);
+ self.port_inc.0
+ }
+
+ pub fn mask_origin_user(&mut self, user: &str) -> String {
+ self.origin_users.mask(user)
+ }
+
+ pub fn mask_ice_password(&mut self, password: &str) -> String {
+ self.ice_passwords.mask(password)
+ }
+
+ pub fn mask_ice_user(&mut self, user: &str) -> String {
+ self.ice_users.mask(user)
+ }
+
+ pub fn mask_cert_finger_print(&mut self, finger_print: &[u8]) -> Vec<u8> {
+ if let Some(stored) = self.cert_finger_prints.get(finger_print) {
+ return stored.clone();
+ }
+ self.cert_finger_print_inc += Wrapping(1);
+ self.cert_finger_prints.insert(
+ finger_print.to_vec(),
+ self.cert_finger_print_inc.0.to_byte_vec(),
+ );
+ self.cert_finger_print_inc.0.to_byte_vec()
+ }
+
+ pub fn mask_cname(&mut self, cname: &str) -> String {
+ self.cnames.mask(cname)
+ }
+}
+
+struct AnonymizationStrMap {
+ map: HashMap<String, String>,
+ counter: Wrapping<u64>,
+ prefix: &'static str,
+ padding: usize,
+}
+
+impl AnonymizationStrMap {
+ pub fn new(prefix: &'static str, padding: usize) -> Self {
+ Self {
+ map: HashMap::new(),
+ counter: Wrapping(0),
+ prefix,
+ padding,
+ }
+ }
+
+ pub fn mask(&mut self, value: &str) -> String {
+ let key = value.to_owned();
+ if let Some(stored) = self.map.get(&key) {
+ return stored.clone();
+ }
+ self.counter += Wrapping(1);
+ let store = format!(
+ "{}{:0padding$}",
+ self.prefix,
+ self.counter.0,
+ padding = self.padding
+ );
+ self.map.insert(key, store.clone());
+ store
+ }
+}
+
+#[cfg(test)]
+#[path = "./anonymizer_tests.rs"]
+mod tests;