Skip to content

Commit fb34990

Browse files
committed
wip check remote component version in server middleware
1 parent 005f4a0 commit fb34990

File tree

3 files changed

+82
-6
lines changed

3 files changed

+82
-6
lines changed

crates/defguard_core/src/grpc/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ use self::{
5151
interceptor::JwtInterceptor, proto::worker::worker_service_server::WorkerServiceServer,
5252
worker::WorkerServer,
5353
};
54+
#[cfg(feature = "wireguard")]
55+
use crate::version::MIN_GATEWAY_VERSION;
5456
use crate::{
5557
VERSION,
5658
auth::failed_login::FailedLoginMap,
@@ -983,7 +985,11 @@ pub async fn run_grpc_server(
983985
#[cfg(feature = "wireguard")]
984986
let router = router.add_service(
985987
ServiceBuilder::new()
986-
.layer(DefguardVersionLayer::new(Version::parse(VERSION)?))
988+
.layer(DefguardVersionLayer::new(
989+
Version::parse(VERSION)?,
990+
DefguardComponent::Gateway,
991+
MIN_GATEWAY_VERSION,
992+
))
987993
.service(gateway_service),
988994
);
989995
#[cfg(feature = "worker")]

crates/defguard_core/src/version.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use defguard_version::Version;
22

3-
const MIN_PROXY_VERSION: Version = Version::new(1, 5, 0);
4-
const MIN_GATEWAY_VERSION: Version = Version::new(1, 6, 0);
3+
const MIN_PROXY_VERSION: Version = Version::new(1, 6, 0);
4+
pub const MIN_GATEWAY_VERSION: Version = Version::new(1, 6, 0);
55

66
/// Checks if the proxy version meets minimum version requirements.
77
pub(crate) fn is_proxy_version_supported(version: Option<&Version>) -> bool {

crates/defguard_version/src/server.rs

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
//! .service(my_grpc_service);
2626
//! ```
2727
28-
use http::HeaderValue;
28+
use http::{HeaderMap, HeaderValue};
2929
use std::{
3030
future::Future,
3131
pin::Pin,
@@ -37,8 +37,11 @@ use tonic::{
3737
server::NamedService,
3838
};
3939
use tower::{Layer, Service};
40+
use tracing::{error, info, warn};
4041

41-
use crate::{ComponentInfo, SYSTEM_INFO_HEADER, VERSION_HEADER};
42+
use crate::{
43+
ComponentInfo, DefguardComponent, SYSTEM_INFO_HEADER, SystemInfo, VERSION_HEADER, Version,
44+
};
4245

4346
/// A tower `Layer` that adds Defguard version and system information headers to gRPC responses.
4447
///
@@ -53,6 +56,8 @@ use crate::{ComponentInfo, SYSTEM_INFO_HEADER, VERSION_HEADER};
5356
#[derive(Clone)]
5457
pub struct DefguardVersionLayer {
5558
component_info: ComponentInfo,
59+
remote_component: DefguardComponent,
60+
remote_component_min_version: Version,
5661
}
5762

5863
impl DefguardVersionLayer {
@@ -66,9 +71,15 @@ impl DefguardVersionLayer {
6671
///
6772
/// * `Ok(DefguardVersionLayer)` - A new layer instance
6873
/// * `Err(DefguardVersionError)` - If the version string cannot be parsed
69-
pub fn new(version: crate::Version) -> Self {
74+
pub fn new(
75+
version: Version,
76+
remote_component: DefguardComponent,
77+
remote_component_min_version: Version,
78+
) -> Self {
7079
Self {
7180
component_info: ComponentInfo::new(version),
81+
remote_component,
82+
remote_component_min_version,
7283
}
7384
}
7485
}
@@ -80,6 +91,8 @@ impl<S> Layer<S> for DefguardVersionLayer {
8091
DefguardVersionService {
8192
inner,
8293
component_info: self.component_info.clone(),
94+
remote_component: self.remote_component.clone(),
95+
remote_component_min_version: self.remote_component_min_version.clone(),
8396
}
8497
}
8598
}
@@ -102,6 +115,55 @@ impl<S> Layer<S> for DefguardVersionLayer {
102115
pub struct DefguardVersionService<S> {
103116
inner: S,
104117
component_info: ComponentInfo,
118+
remote_component: DefguardComponent,
119+
remote_component_min_version: Version,
120+
}
121+
122+
impl<S> DefguardVersionService<S> {
123+
/// Checks if remote component version meets minimum version requirements.
124+
fn is_version_supported(&self, version: Option<&Version>) -> bool {
125+
let Some(version) = version else {
126+
error!(
127+
"Missing core component version information. This most likely means that core component uses unsupported version."
128+
);
129+
return false;
130+
};
131+
if version < &self.remote_component_min_version {
132+
error!(
133+
"{} version {version} is not supported. Minimal supported {} version is {}.",
134+
self.remote_component, self.remote_component, self.remote_component_min_version
135+
);
136+
return false;
137+
}
138+
139+
info!("{} version {version} is supported", self.remote_component);
140+
true
141+
}
142+
143+
pub fn parse_headers(metadata: &HeaderMap) -> Option<ComponentInfo> {
144+
let Some(version) = metadata.get(VERSION_HEADER) else {
145+
warn!("Missing version header");
146+
return None;
147+
};
148+
let Some(system) = metadata.get(SYSTEM_INFO_HEADER) else {
149+
warn!("Missing system info header");
150+
return None;
151+
};
152+
let (Ok(version), Ok(system)) = (version.to_str(), system.to_str()) else {
153+
warn!("Failed to stringify version or system info header value");
154+
return None;
155+
};
156+
let Ok(version) = Version::parse(version) else {
157+
warn!("Failed to parse version: {version}");
158+
return None;
159+
};
160+
let Ok(system) = SystemInfo::try_from_header_value(system) else {
161+
warn!("Failed to parse system info: {system}");
162+
return None;
163+
};
164+
165+
Some(ComponentInfo { version, system })
166+
}
105167
}
106168

107169
impl<S, B> Service<Request<Body>> for DefguardVersionService<S>
@@ -136,7 +198,15 @@ where
136198
.ok(),
137199
);
138200

201+
// Check remote component version
202+
let maybe_info = Self::parse_headers(request.headers());
203+
let version = maybe_info.as_ref().map(|info| &info.version);
204+
let is_remote_version_supported = self.is_version_supported(version);
139205
Box::pin(async move {
206+
if !is_remote_version_supported {
207+
// TODO: return error response
208+
error!("REMOTE VERSION NOT SUPPORTED");
209+
}
140210
// Process the request with the inner service first
141211
let mut response = inner.call(request).await?;
142212

0 commit comments

Comments
 (0)