Skip to content

Commit 6f56cf5

Browse files
committed
refactor(nmrs): helper struct for OvpnFile building and Compress refining
1 parent e3fc4a7 commit 6f56cf5

1 file changed

Lines changed: 78 additions & 63 deletions

File tree

nmrs/src/core/ovpn_parser/parser.rs

Lines changed: 78 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ pub struct OvpnFile {
5555
pub auth: Option<String>,
5656

5757
// compress directive. Either enabled or specifies algorithm (e.g. "lz4").
58-
pub compress: Option<String>,
58+
pub compress: Option<Compress>,
5959

6060
// OpenVPN 2.5+ specifies a allow-compress directive for safety
6161
// https://community.openvpn.net/Security%20Announcements/VORACLE
@@ -98,6 +98,13 @@ pub struct TlsAuth {
9898
pub key_direction: Option<u8>,
9999
}
100100

101+
#[derive(Debug, Clone)]
102+
pub enum Compress {
103+
Stub,
104+
StubV2,
105+
Algorithm(String),
106+
}
107+
101108
#[derive(Debug, Clone)]
102109
pub enum AllowCompress {
103110
Yes,
@@ -127,6 +134,51 @@ enum OvpnItem {
127134
Block { key: String, content: String },
128135
}
129136

137+
#[derive(Default)]
138+
struct OvpnFileBuilder {
139+
remotes: Vec<Remote>,
140+
dev: Option<String>,
141+
proto: Option<String>,
142+
ca: Option<CertSource>,
143+
cert: Option<CertSource>,
144+
key: Option<CertSource>,
145+
tls_auth: Option<TlsAuth>,
146+
tls_crypt: Option<CertSource>,
147+
cipher: Option<String>,
148+
data_ciphers: Vec<String>,
149+
auth: Option<String>,
150+
compress: Option<Compress>,
151+
allow_compress: Option<AllowCompress>,
152+
routes: Vec<Route>,
153+
redirect_gateway: Option<RedirectGateway>,
154+
flags: Vec<String>,
155+
options: HashMap<String, Vec<String>>,
156+
}
157+
158+
impl OvpnFileBuilder {
159+
fn build(self) -> OvpnFile {
160+
OvpnFile {
161+
remotes: self.remotes,
162+
dev: self.dev,
163+
proto: self.proto,
164+
ca: self.ca,
165+
cert: self.cert,
166+
key: self.key,
167+
tls_auth: self.tls_auth,
168+
tls_crypt: self.tls_crypt,
169+
cipher: self.cipher,
170+
data_ciphers: self.data_ciphers,
171+
auth: self.auth,
172+
compress: self.compress,
173+
allow_compress: self.allow_compress,
174+
routes: self.routes,
175+
redirect_gateway: self.redirect_gateway,
176+
flags: self.flags,
177+
options: self.options,
178+
}
179+
}
180+
}
181+
130182
fn lexer(input: &str) -> Result<Vec<OvpnItem>, OvpnParseError> {
131183
let mut items = Vec::new();
132184

@@ -262,24 +314,7 @@ fn lexer(input: &str) -> Result<Vec<OvpnItem>, OvpnParseError> {
262314
}
263315

264316
pub fn parse_ovpn(content: &str) -> Result<OvpnFile, ConnectionError> {
265-
let mut remotes: Vec<Remote> = Vec::new();
266-
let mut dev: Option<String> = None;
267-
let mut proto: Option<String> = None;
268-
let mut ca: Option<CertSource> = None;
269-
let mut cert: Option<CertSource> = None;
270-
let mut key: Option<CertSource> = None;
271-
let mut tls_auth: Option<TlsAuth> = None;
272-
let mut tls_crypt: Option<CertSource> = None;
273-
let mut cipher: Option<String> = None;
274-
let mut data_ciphers: Vec<String> = Vec::new();
275-
let mut auth: Option<String> = None;
276-
let mut compress: Option<String> = None;
277-
let mut allow_compress: Option<AllowCompress> = None;
278-
let mut routes: Vec<Route> = Vec::new();
279-
let mut redirect_gateway: Option<RedirectGateway> = None;
280-
let mut flags: Vec<String> = Vec::new();
281-
let mut options: HashMap<String, Vec<String>> = HashMap::new();
282-
317+
let mut b = OvpnFileBuilder::default();
283318
let items = lexer(content)?;
284319

285320
for item in items {
@@ -304,7 +339,7 @@ pub fn parse_ovpn(content: &str) -> Result<OvpnFile, ConnectionError> {
304339

305340
let proto = args.get(2).cloned();
306341

307-
remotes.push(Remote { host, port, proto });
342+
b.remotes.push(Remote { host, port, proto });
308343
}
309344
"dev" => {
310345
// dev <DEVICE>
@@ -323,7 +358,7 @@ pub fn parse_ovpn(content: &str) -> Result<OvpnFile, ConnectionError> {
323358
line: 0,
324359
})?;
325360

326-
dev = Some(value.clone());
361+
b.dev = Some(value.clone());
327362
}
328363
"proto" => {
329364
// proto <PROTOCOL>
@@ -334,7 +369,7 @@ pub fn parse_ovpn(content: &str) -> Result<OvpnFile, ConnectionError> {
334369
line: 0,
335370
})?;
336371

337-
proto = Some(value.clone());
372+
b.proto = Some(value.clone());
338373
}
339374
"cipher" => {
340375
// cipher <CIPHER>
@@ -346,7 +381,7 @@ pub fn parse_ovpn(content: &str) -> Result<OvpnFile, ConnectionError> {
346381
line: 0,
347382
})?;
348383

349-
cipher = Some(value.clone());
384+
b.cipher = Some(value.clone());
350385
}
351386
"data-ciphers" => {
352387
// data-ciphers <[cipher1]:[cipher2]...>
@@ -357,7 +392,7 @@ pub fn parse_ovpn(content: &str) -> Result<OvpnFile, ConnectionError> {
357392
line: 0,
358393
})?;
359394

360-
data_ciphers.extend(ciphers.split(':').map(String::from));
395+
b.data_ciphers.extend(ciphers.split(':').map(String::from));
361396
}
362397
"auth" => {
363398
// auth <ALGORITHM>
@@ -368,18 +403,16 @@ pub fn parse_ovpn(content: &str) -> Result<OvpnFile, ConnectionError> {
368403
line: 0,
369404
})?;
370405

371-
auth = Some(value.clone());
406+
b.auth = Some(value.clone());
372407
}
373408
"compress" => {
374-
// compress <ALGORITHM>
375-
376-
let value = args.get(0).ok_or(OvpnParseError::InvalidArgument {
377-
key,
378-
arg: "".into(),
379-
line: 0,
380-
})?;
409+
// compress [ALGORITHM]
381410

382-
compress = Some(value.clone());
411+
b.compress = Some(match args.first().map(|s| s.as_str()) {
412+
None | Some("stub") => Compress::Stub,
413+
Some("stub-v2") => Compress::StubV2,
414+
Some(alg) => Compress::Algorithm(alg.to_string()),
415+
});
383416
}
384417
"allow-compress" => {
385418
// allow-compress asym (default) <- receive compressed data but don't send
@@ -398,7 +431,7 @@ pub fn parse_ovpn(content: &str) -> Result<OvpnFile, ConnectionError> {
398431
other => AllowCompress::Other(other.to_string()),
399432
};
400433

401-
allow_compress = Some(parsed);
434+
b.allow_compress = Some(parsed);
402435
}
403436
"route" => {
404437
// route <NETWORK> [NETMASK] [GATEWAY]
@@ -413,7 +446,7 @@ pub fn parse_ovpn(content: &str) -> Result<OvpnFile, ConnectionError> {
413446
.map(|v| parse_ipv4_arg(&key, Some(v), 0))
414447
.transpose()?;
415448

416-
routes.push(Route {
449+
b.routes.push(Route {
417450
network,
418451
netmask,
419452
gateway,
@@ -439,13 +472,13 @@ pub fn parse_ovpn(content: &str) -> Result<OvpnFile, ConnectionError> {
439472
}
440473
}
441474

442-
redirect_gateway = Some(rg);
475+
b.redirect_gateway = Some(rg);
443476
}
444477
_ => {
445478
if args.is_empty() {
446-
flags.push(key);
479+
b.flags.push(key);
447480
} else {
448-
options.entry(key).or_default().extend(args);
481+
b.options.entry(key).or_default().extend(args);
449482
}
450483
}
451484
}
@@ -456,55 +489,37 @@ pub fn parse_ovpn(content: &str) -> Result<OvpnFile, ConnectionError> {
456489
} => {
457490
match block_key.as_str() {
458491
"ca" => {
459-
ca = Some(CertSource::Inline(content));
492+
b.ca = Some(CertSource::Inline(content));
460493
}
461494

462495
"cert" => {
463-
cert = Some(CertSource::Inline(content));
496+
b.cert = Some(CertSource::Inline(content));
464497
}
465498

466499
"key" => {
467-
key = Some(CertSource::Inline(content));
500+
b.key = Some(CertSource::Inline(content));
468501
}
469502

470503
"tls-auth" => {
471-
tls_auth = Some(TlsAuth {
504+
b.tls_auth = Some(TlsAuth {
472505
source: CertSource::Inline(content),
473506
key_direction: None, // FIXME: handle seperately
474507
});
475508
}
476509

477510
"tls-crypt" => {
478-
tls_crypt = Some(CertSource::Inline(content));
511+
b.tls_crypt = Some(CertSource::Inline(content));
479512
}
480513

481514
_ => {
482-
options.entry(block_key).or_default().push(content);
515+
b.options.entry(block_key).or_default().push(content);
483516
}
484517
}
485518
}
486519
}
487520
}
488521

489-
Ok(OvpnFile {
490-
remotes,
491-
dev,
492-
proto,
493-
ca,
494-
cert,
495-
key,
496-
tls_auth,
497-
tls_crypt,
498-
cipher,
499-
data_ciphers,
500-
auth,
501-
compress,
502-
allow_compress,
503-
routes,
504-
redirect_gateway,
505-
flags,
506-
options,
507-
})
522+
Ok(b.build())
508523
}
509524

510525
fn parse_ipv4_arg(

0 commit comments

Comments
 (0)