@@ -4,260 +4,11 @@ mod set_identity_header;
44#[ cfg( test) ]
55mod tests;
66
7+ #[ cfg( fuzzing) ]
8+ pub mod fuzz;
9+
710fn 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