forked from mitmproxy/mitmproxy_rs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
intercept_conf.rs
executable file
·152 lines (135 loc) · 4.19 KB
/
intercept_conf.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
use anyhow::bail;
use std::collections::HashSet;
pub type PID = u32;
#[derive(Debug, Clone)]
pub struct ProcessInfo {
pub pid: PID,
pub process_name: Option<String>,
}
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct InterceptConf {
pub pids: HashSet<PID>,
pub process_names: Vec<String>,
/// if true, matching items are the ones which are not intercepted.
pub invert: bool,
}
impl TryFrom<&str> for InterceptConf {
type Error = anyhow::Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let mut val = value.trim();
if val.is_empty() {
return Ok(InterceptConf::new(vec![], vec![], false));
}
let invert = if val.starts_with('!') {
val = &val[1..];
true
} else {
false
};
let mut pids = vec![];
let mut procs = vec![];
for part in val.split(',') {
let part = part.trim();
if part.is_empty() {
bail!("invalid intercept spec: {}", value);
}
match part.parse::<PID>() {
Ok(pid) => pids.push(pid),
Err(_) => procs.push(part.to_string()),
}
}
Ok(InterceptConf::new(pids, procs, invert))
}
}
impl ToString for InterceptConf {
fn to_string(&self) -> String {
let spec = self
.pids
.iter()
.map(|x| x.to_string())
.chain(self.process_names.clone())
.collect::<Vec<String>>()
.join(",");
if self.invert {
format!("!{}", spec)
} else {
spec
}
}
}
impl InterceptConf {
pub fn new(pids: Vec<PID>, process_names: Vec<String>, invert: bool) -> Self {
let pids = HashSet::from_iter(pids);
if invert {
assert!(!pids.is_empty() || !process_names.is_empty());
}
Self {
pids,
process_names,
invert,
}
}
pub fn should_intercept(&self, process_info: &ProcessInfo) -> bool {
self.invert ^ {
if self.pids.contains(&process_info.pid) {
true
} else if let Some(name) = &process_info.process_name {
self.process_names.iter().any(|n| name.contains(n))
} else {
false
}
}
}
pub fn description(&self) -> String {
if self.pids.is_empty() && self.process_names.is_empty() {
return "Intercept nothing.".to_string();
}
let mut parts = vec![];
if !self.pids.is_empty() {
parts.push(format!("pids: {:?}", self.pids));
}
if !self.process_names.is_empty() {
parts.push(format!("process names: {:?}", self.process_names));
}
let start = if self.invert {
"Intercepting all packets but those from "
} else {
"Intercepting packets from "
};
format!("{}{}", start, parts.join(" or "))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_intercept_conf() {
let a = ProcessInfo {
pid: 1,
process_name: Some("a".into()),
};
let b = ProcessInfo {
pid: 2242,
process_name: Some("mitmproxy".into()),
};
let conf = InterceptConf::try_from("1,2,3").unwrap();
assert_eq!(conf.pids, vec![1, 2, 3].into_iter().collect());
assert!(conf.process_names.is_empty());
assert!(!conf.invert);
assert!(conf.should_intercept(&a));
assert!(!conf.should_intercept(&b));
let conf = InterceptConf::try_from("").unwrap();
assert!(conf.pids.is_empty());
assert!(conf.process_names.is_empty());
assert!(!conf.invert);
assert!(!conf.should_intercept(&a));
assert!(!conf.should_intercept(&b));
let conf = InterceptConf::try_from("!2242").unwrap();
assert_eq!(conf.pids, vec![2242].into_iter().collect());
assert!(conf.process_names.is_empty());
assert!(conf.invert);
assert!(conf.should_intercept(&a));
assert!(!conf.should_intercept(&b));
assert!(InterceptConf::try_from(",,").is_err());
}
}