Skip to content

Commit e77fe18

Browse files
authored
outbound: Prevent loops (#525)
This change modifies the outbound proxy to fail to build services targetting localhost:4140 (where 4140 is the outbound port). This prevents looping and will result in 502s.
1 parent fd5a6aa commit e77fe18

File tree

8 files changed

+53
-7
lines changed

8 files changed

+53
-7
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,7 @@ dependencies = [
633633
"indexmap",
634634
"libc",
635635
"linkerd2-addr",
636+
"linkerd2-admit",
636637
"linkerd2-box",
637638
"linkerd2-buffer",
638639
"linkerd2-cache",
@@ -700,7 +701,6 @@ dependencies = [
700701
"futures",
701702
"http",
702703
"indexmap",
703-
"linkerd2-admit",
704704
"linkerd2-app-core",
705705
"quickcheck",
706706
"tokio",

linkerd/app/core/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ hyper = "0.12"
2121
futures = "0.1"
2222
indexmap = "1.0"
2323
linkerd2-addr = { path = "../../addr" }
24+
linkerd2-admit = { path = "../../admit" }
2425
linkerd2-cache = { path = "../../cache" }
2526
linkerd2-box = { path = "../../box" }
2627
linkerd2-buffer = { path = "../../buffer" }

linkerd/app/core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#![deny(warnings, rust_2018_idioms)]
1111

1212
pub use linkerd2_addr::{self as addr, Addr, NameAddr};
13+
pub use linkerd2_admit as admit;
1314
pub use linkerd2_cache as cache;
1415
pub use linkerd2_conditional::Conditional;
1516
pub use linkerd2_drain as drain;

linkerd/app/inbound/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ bytes = "0.4"
1313
http = "0.1"
1414
futures = "0.1"
1515
indexmap = "1.0"
16-
linkerd2-admit = { path = "../../admit" }
1716
linkerd2-app-core = { path = "../core" }
1817
tokio = "0.1.14"
1918
tower = "0.1"

linkerd/app/inbound/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@ pub use self::endpoint::{
1010
};
1111
use self::require_identity_for_ports::RequireIdentityForPorts;
1212
use futures::future;
13-
use linkerd2_admit as admit;
1413
use linkerd2_app_core::{
15-
classify,
14+
admit, classify,
1615
config::{ProxyConfig, ServerConfig},
1716
drain, dst, errors, metric_labels,
1817
opencensus::proto::trace::v1 as oc,

linkerd/app/inbound/src/require_identity_for_ports.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use indexmap::IndexSet;
2-
use linkerd2_admit as admit;
3-
use linkerd2_app_core::transport::tls;
2+
use linkerd2_app_core::{admit, transport::tls};
43
use std::sync::Arc;
54

65
/// A connection policy that drops

linkerd/app/outbound/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub use self::endpoint::{
1212
use ::http::header::HOST;
1313
use futures::future;
1414
use linkerd2_app_core::{
15-
classify,
15+
admit, classify,
1616
config::{ProxyConfig, ServerConfig},
1717
dns, drain, dst, errors, metric_labels,
1818
opencensus::proto::trace::v1 as oc,
@@ -40,9 +40,11 @@ mod add_remote_ip_on_rsp;
4040
mod add_server_id_on_rsp;
4141
mod endpoint;
4242
mod orig_proto_upgrade;
43+
mod prevent_loop;
4344
mod require_identity_on_endpoint;
4445

4546
use self::orig_proto_upgrade::OrigProtoUpgradeLayer;
47+
use self::prevent_loop::PreventLoop;
4648
use self::require_identity_on_endpoint::MakeRequireIdentityLayer;
4749

4850
const EWMA_DEFAULT_RTT: Duration = Duration::from_millis(30);
@@ -156,6 +158,7 @@ impl Config {
156158
let backoff = connect.backoff.clone();
157159
move |_| Ok(backoff.stream())
158160
}))
161+
.push(admit::AdmitLayer::new(PreventLoop::new(listen_addr.port())))
159162
.push(observability.clone())
160163
.push(identity_headers.clone())
161164
.push(http::override_authority::Layer::new(vec![HOST.as_str(), CANONICAL_DST_HEADER]))
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use super::endpoint::{HttpEndpoint, Target};
2+
use linkerd2_app_core::admit;
3+
4+
/// A connection policy that drops
5+
#[derive(Copy, Clone, Debug)]
6+
pub struct PreventLoop {
7+
port: u16,
8+
}
9+
10+
#[derive(Copy, Clone, Debug)]
11+
pub struct LoopPrevented {
12+
port: u16,
13+
}
14+
15+
impl PreventLoop {
16+
pub fn new(port: u16) -> Self {
17+
Self { port }
18+
}
19+
}
20+
21+
impl admit::Admit<Target<HttpEndpoint>> for PreventLoop {
22+
type Error = LoopPrevented;
23+
24+
fn admit(&mut self, ep: &Target<HttpEndpoint>) -> Result<(), Self::Error> {
25+
tracing::debug!(addr = %ep.inner.addr, self.port);
26+
if ep.inner.addr.ip().is_loopback() && ep.inner.addr.port() == self.port {
27+
return Err(LoopPrevented { port: self.port });
28+
}
29+
30+
Ok(())
31+
}
32+
}
33+
34+
impl std::fmt::Display for LoopPrevented {
35+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36+
write!(
37+
f,
38+
"outbound requests must not target localhost:{}",
39+
self.port
40+
)
41+
}
42+
}
43+
44+
impl std::error::Error for LoopPrevented {}

0 commit comments

Comments
 (0)