Skip to content

Commit 8c1a04f

Browse files
authored
refactor(app/inbound): move fuzzing into submodule (#4123)
this commit moves the fuzzing facilities in `linkerd-app-inbound` into a submodule. no changes are made, besides code motion. Signed-off-by: katelyn martin <[email protected]>
1 parent 313a6f3 commit 8c1a04f

File tree

2 files changed

+246
-252
lines changed

2 files changed

+246
-252
lines changed

linkerd/app/inbound/src/http.rs

Lines changed: 3 additions & 252 deletions
Original file line numberDiff line numberDiff line change
@@ -4,260 +4,11 @@ mod set_identity_header;
44
#[cfg(test)]
55
mod tests;
66

7+
#[cfg(fuzzing)]
8+
pub mod fuzz;
9+
710
fn trace_labels() -> std::collections::HashMap<String, String> {
811
let mut l = std::collections::HashMap::new();
912
l.insert("direction".to_string(), "inbound".to_string());
1013
l
1114
}
12-
13-
#[cfg(fuzzing)]
14-
pub mod fuzz {
15-
use crate::{
16-
http::router::Http,
17-
policy,
18-
test_util::{support::connect::Connect, *},
19-
Config, Inbound,
20-
};
21-
use hyper::{Body, Request, Response};
22-
use libfuzzer_sys::arbitrary::Arbitrary;
23-
use linkerd_app_core::{
24-
identity, io,
25-
proxy::http,
26-
svc::{self, NewService},
27-
tls,
28-
transport::{ClientAddr, OrigDstAddr, Remote, ServerAddr},
29-
NameAddr, ProxyRuntime,
30-
};
31-
pub use linkerd_app_test as support;
32-
use linkerd_app_test::*;
33-
use std::{fmt, str, sync::Arc};
34-
35-
#[derive(Arbitrary)]
36-
pub struct HttpRequestSpec {
37-
pub uri: Vec<u8>,
38-
pub header_name: Vec<u8>,
39-
pub header_value: Vec<u8>,
40-
pub http_method: bool,
41-
}
42-
43-
pub async fn fuzz_entry_raw(requests: Vec<HttpRequestSpec>) {
44-
let server = hyper::server::conn::http1::Builder::new();
45-
let mut client = hyper::client::conn::http1::Builder::new();
46-
let connect =
47-
support::connect().endpoint_fn_boxed(Target::addr(), hello_fuzz_server(server));
48-
let profiles = profile::resolver();
49-
let profile_tx = profiles
50-
.profile_tx(NameAddr::from_str_and_port("foo.svc.cluster.local", 5550).unwrap());
51-
profile_tx.send(profile::Profile::default()).unwrap();
52-
53-
// Build the outbound server
54-
let cfg = default_config();
55-
let (rt, _shutdown) = runtime();
56-
let server = build_fuzz_server(cfg, rt, profiles, connect).new_service(Target::HTTP1);
57-
let (mut client, bg) = http_util::connect_and_accept_http1(&mut client, server).await;
58-
59-
// Now send all of the requests
60-
for inp in requests.iter() {
61-
if let Ok(uri) = std::str::from_utf8(&inp.uri[..]) {
62-
if let Ok(header_name) = std::str::from_utf8(&inp.header_name[..]) {
63-
if let Ok(header_value) = std::str::from_utf8(&inp.header_value[..]) {
64-
let http_method = if inp.http_method {
65-
hyper::http::Method::GET
66-
} else {
67-
hyper::http::Method::POST
68-
};
69-
70-
if let Ok(req) = Request::builder()
71-
.method(http_method)
72-
.uri(uri)
73-
.header(header_name, header_value)
74-
.body(Body::default())
75-
{
76-
let rsp = client.send_request(req).await;
77-
tracing::info!(?rsp);
78-
if let Ok(rsp) = rsp {
79-
let body = http_util::body_to_string(rsp.into_body()).await;
80-
tracing::info!(?body);
81-
}
82-
}
83-
}
84-
}
85-
}
86-
}
87-
88-
// It's okay if the background task returns an error, as this would
89-
// indicate that the proxy closed the connection --- which it will do on
90-
// invalid inputs. We want to ensure that the proxy doesn't crash in the
91-
// face of these inputs, and the background task will panic in this
92-
// case.
93-
drop(client);
94-
let res = bg.join_all().await;
95-
tracing::info!(?res, "background tasks completed")
96-
}
97-
98-
fn hello_fuzz_server(
99-
http: hyper::server::conn::http1::Builder,
100-
) -> impl Fn(Remote<ServerAddr>) -> io::Result<io::BoxedIo> {
101-
move |_endpoint| {
102-
let (client_io, server_io) = support::io::duplex(4096);
103-
let hello_svc = hyper::service::service_fn(|_request: Request<Body>| async move {
104-
Ok::<_, io::Error>(Response::new(Body::from("Hello world!")))
105-
});
106-
tokio::spawn(
107-
http.serve_connection(server_io, hello_svc)
108-
.in_current_span(),
109-
);
110-
Ok(io::BoxedIo::new(client_io))
111-
}
112-
}
113-
114-
fn build_fuzz_server<I>(
115-
cfg: Config,
116-
rt: ProxyRuntime,
117-
profiles: resolver::Profiles,
118-
connect: Connect<Remote<ServerAddr>>,
119-
) -> svc::ArcNewTcp<Target, I>
120-
where
121-
I: io::AsyncRead + io::AsyncWrite + io::PeerAddr + Send + Unpin + 'static,
122-
{
123-
let connect = svc::stack(connect)
124-
.push_map_target(|t: Http| svc::Param::<Remote<ServerAddr>>::param(&t))
125-
.into_inner();
126-
Inbound::new(cfg, rt)
127-
.with_stack(connect)
128-
.push_http_router(profiles)
129-
.push_http_server()
130-
.push_http_tcp_server()
131-
.into_inner()
132-
}
133-
134-
impl fmt::Debug for HttpRequestSpec {
135-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136-
// Custom `Debug` impl that formats the URI, header name, and header
137-
// value as strings if they are UTF-8, or falls back to raw bytes
138-
// otherwise.
139-
let mut dbg = f.debug_struct("HttpRequestSpec");
140-
dbg.field("http_method", &self.http_method);
141-
142-
if let Ok(uri) = str::from_utf8(&self.uri[..]) {
143-
dbg.field("uri", &uri);
144-
} else {
145-
dbg.field("uri", &self.uri);
146-
}
147-
148-
if let Ok(name) = str::from_utf8(&self.header_name[..]) {
149-
dbg.field("header_name", &name);
150-
} else {
151-
dbg.field("header_name", &self.header_name);
152-
}
153-
154-
if let Ok(value) = str::from_utf8(&self.header_value[..]) {
155-
dbg.field("header_value", &value);
156-
} else {
157-
dbg.field("header_value", &self.header_value);
158-
}
159-
160-
dbg.finish()
161-
}
162-
}
163-
164-
#[derive(Clone, Debug)]
165-
struct Target(http::Variant);
166-
167-
// === impl Target ===
168-
169-
impl Target {
170-
const HTTP1: Self = Self(http::Variant::Http1);
171-
172-
fn addr() -> SocketAddr {
173-
([127, 0, 0, 1], 80).into()
174-
}
175-
}
176-
177-
impl svc::Param<OrigDstAddr> for Target {
178-
fn param(&self) -> OrigDstAddr {
179-
OrigDstAddr(Self::addr())
180-
}
181-
}
182-
183-
impl svc::Param<Remote<ServerAddr>> for Target {
184-
fn param(&self) -> Remote<ServerAddr> {
185-
Remote(ServerAddr(Self::addr()))
186-
}
187-
}
188-
189-
impl svc::Param<Remote<ClientAddr>> for Target {
190-
fn param(&self) -> Remote<ClientAddr> {
191-
Remote(ClientAddr(([192, 0, 2, 3], 50000).into()))
192-
}
193-
}
194-
195-
impl svc::Param<http::Variant> for Target {
196-
fn param(&self) -> http::Variant {
197-
self.0
198-
}
199-
}
200-
201-
impl svc::Param<tls::ConditionalServerTls> for Target {
202-
fn param(&self) -> tls::ConditionalServerTls {
203-
tls::ConditionalServerTls::None(tls::NoServerTls::NoClientHello)
204-
}
205-
}
206-
207-
impl svc::Param<policy::AllowPolicy> for Target {
208-
fn param(&self) -> policy::AllowPolicy {
209-
let (policy, _) = policy::AllowPolicy::for_test(
210-
self.param(),
211-
policy::ServerPolicy {
212-
protocol: policy::Protocol::Http1(Arc::new([
213-
linkerd_proxy_server_policy::http::default(Arc::new([
214-
policy::Authorization {
215-
authentication: policy::Authentication::Unauthenticated,
216-
networks: vec![std::net::IpAddr::from([192, 0, 2, 3]).into()],
217-
meta: Arc::new(policy::Meta::Resource {
218-
group: "policy.linkerd.io".into(),
219-
kind: "server".into(),
220-
name: "testsaz".into(),
221-
}),
222-
},
223-
])),
224-
])),
225-
meta: Arc::new(policy::Meta::Resource {
226-
group: "policy.linkerd.io".into(),
227-
kind: "server".into(),
228-
name: "testsrv".into(),
229-
}),
230-
local_rate_limit: Arc::new(
231-
linkerd_proxy_server_policy::LocalRateLimit::default(),
232-
),
233-
},
234-
);
235-
policy
236-
}
237-
}
238-
239-
impl svc::Param<policy::ServerLabel> for Target {
240-
fn param(&self) -> policy::ServerLabel {
241-
policy::ServerLabel(
242-
Arc::new(policy::Meta::Resource {
243-
group: "policy.linkerd.io".into(),
244-
kind: "server".into(),
245-
name: "testsrv".into(),
246-
}),
247-
1000,
248-
)
249-
}
250-
}
251-
252-
impl svc::Param<http::normalize_uri::DefaultAuthority> for Target {
253-
fn param(&self) -> http::normalize_uri::DefaultAuthority {
254-
http::normalize_uri::DefaultAuthority(None)
255-
}
256-
}
257-
258-
impl svc::Param<Option<identity::Id>> for Target {
259-
fn param(&self) -> Option<identity::Id> {
260-
None
261-
}
262-
}
263-
}

0 commit comments

Comments
 (0)