22//!
33//! Matches the managed host's argument convention (see `RenderingManager.GetConnectionParameters`).
44
5- use std:: env:: { self , VarError } ;
5+ use std:: env;
66use std:: mem:: size_of;
77use std:: net:: UdpSocket ;
88use std:: num:: TryFromIntError ;
@@ -15,14 +15,6 @@ use thiserror::Error;
1515const ATTACH_RENDERER_PORT : u16 = 42_512 ;
1616/// Maximum accepted attach handshake payload size.
1717const ATTACH_RENDERER_PACKET_MAX_BYTES : usize = 4096 ;
18- /// Environment variable carrying the debug-attach v2 nonce.
19- pub const ATTACH_RENDERER_NONCE_ENV : & str = "RENDERIDE_ATTACH_NONCE" ;
20- /// Magic prefix for authenticated debug-attach v2 packets.
21- const ATTACH_RENDERER_V2_MAGIC : & [ u8 ] = b"RenderideAttachV2\0 " ;
22- /// Minimum nonce length accepted for debug attach.
23- const ATTACH_RENDERER_MIN_NONCE_BYTES : usize = 16 ;
24- /// Maximum nonce length accepted for debug attach.
25- const ATTACH_RENDERER_MAX_NONCE_BYTES : usize = 128 ;
2618/// Maximum number of bytes in a .NET 7-bit encoded i32.
2719const MAX_7BIT_ENCODED_I32_BYTES : usize = 5 ;
2820/// High bit marking another 7-bit length byte.
@@ -52,24 +44,6 @@ enum AttachConnectionError {
5244 /// The attach listener failed while waiting for the host datagram.
5345 #[ error( "failed to receive attach renderer parameters: {0}" ) ]
5446 Receive ( #[ source] std:: io:: Error ) ,
55- /// An authenticated v2 attach packet was received without a configured nonce.
56- #[ error( "attach renderer v2 packet requires {ATTACH_RENDERER_NONCE_ENV}" ) ]
57- MissingNonce ,
58- /// Attach nonce was outside the accepted size range.
59- #[ error( "attach renderer nonce length {len} is outside the accepted range" ) ]
60- InvalidNonceLength {
61- /// Nonce byte length.
62- len : usize ,
63- } ,
64- /// Attach nonce could not be read as a Unicode environment value.
65- #[ error( "attach renderer nonce is not valid Unicode" ) ]
66- InvalidNonceEncoding ,
67- /// The packet was not an authenticated v2 attach packet.
68- #[ error( "attach renderer packet is not an authenticated v2 packet" ) ]
69- MissingV2Magic ,
70- /// The packet nonce does not match the expected launch nonce.
71- #[ error( "attach renderer nonce mismatch" ) ]
72- NonceMismatch ,
7347 /// The payload ended before the queue name length prefix completed.
7448 #[ error( "attach renderer payload ended before the queue name length prefix completed" ) ]
7549 TruncatedStringLength ,
@@ -179,19 +153,7 @@ fn arg_has_ascii_suffix(arg: &str, suffix: &str) -> bool {
179153
180154/// Waits for connection parameters from the debug attach UDP handshake.
181155fn get_connection_parameters_from_attach_renderer ( ) -> Option < ConnectionParams > {
182- let nonce = match attach_renderer_nonce_from_env ( ) {
183- Ok ( nonce) => nonce,
184- Err ( error) => {
185- logger:: warn!( "Attach renderer handshake failed: {error}" ) ;
186- return None ;
187- }
188- } ;
189- if nonce. is_none ( ) {
190- logger:: warn!(
191- "Attach renderer nonce not configured; accepting unauthenticated legacy attach payloads"
192- ) ;
193- }
194- match receive_attach_renderer_parameters ( nonce. as_deref ( ) ) {
156+ match receive_attach_renderer_parameters ( ) {
195157 Ok ( params) => Some ( params) ,
196158 Err ( error) => {
197159 logger:: warn!( "Attach renderer handshake failed: {error}" ) ;
@@ -200,29 +162,8 @@ fn get_connection_parameters_from_attach_renderer() -> Option<ConnectionParams>
200162 }
201163}
202164
203- fn attach_renderer_nonce_from_env ( ) -> Result < Option < Vec < u8 > > , AttachConnectionError > {
204- let nonce = match env:: var ( ATTACH_RENDERER_NONCE_ENV ) {
205- Ok ( nonce) => nonce. into_bytes ( ) ,
206- Err ( VarError :: NotPresent ) => return Ok ( None ) ,
207- Err ( VarError :: NotUnicode ( _nonce) ) => {
208- return Err ( AttachConnectionError :: InvalidNonceEncoding ) ;
209- }
210- } ;
211- validate_attach_renderer_nonce ( & nonce) ?;
212- Ok ( Some ( nonce) )
213- }
214-
215- fn validate_attach_renderer_nonce ( nonce : & [ u8 ] ) -> Result < ( ) , AttachConnectionError > {
216- if !( ATTACH_RENDERER_MIN_NONCE_BYTES ..=ATTACH_RENDERER_MAX_NONCE_BYTES ) . contains ( & nonce. len ( ) ) {
217- return Err ( AttachConnectionError :: InvalidNonceLength { len : nonce. len ( ) } ) ;
218- }
219- Ok ( ( ) )
220- }
221-
222165/// Receives and parses the debug attach UDP datagram.
223- fn receive_attach_renderer_parameters (
224- expected_nonce : Option < & [ u8 ] > ,
225- ) -> Result < ConnectionParams , AttachConnectionError > {
166+ fn receive_attach_renderer_parameters ( ) -> Result < ConnectionParams , AttachConnectionError > {
226167 let socket = UdpSocket :: bind ( ( "127.0.0.1" , ATTACH_RENDERER_PORT ) )
227168 . map_err ( AttachConnectionError :: Bind ) ?;
228169 logger:: info!(
@@ -233,48 +174,11 @@ fn receive_attach_renderer_parameters(
233174 let ( len, _) = socket
234175 . recv_from ( & mut buf)
235176 . map_err ( AttachConnectionError :: Receive ) ?;
236- parse_attach_renderer_packet ( & buf[ ..len] , expected_nonce )
177+ parse_attach_renderer_packet ( & buf[ ..len] )
237178}
238179
239- /// Parses the authenticated host attach datagram.
240- fn parse_attach_renderer_packet (
241- packet : & [ u8 ] ,
242- expected_nonce : Option < & [ u8 ] > ,
243- ) -> Result < ConnectionParams , AttachConnectionError > {
244- let Some ( rest) = packet. strip_prefix ( ATTACH_RENDERER_V2_MAGIC ) else {
245- if expected_nonce. is_some ( ) {
246- return Err ( AttachConnectionError :: MissingV2Magic ) ;
247- }
248- logger:: warn!( "Attach renderer accepted unauthenticated legacy payload" ) ;
249- return parse_attach_renderer_legacy_payload ( packet) ;
250- } ;
251- let Some ( expected_nonce) = expected_nonce else {
252- return Err ( AttachConnectionError :: MissingNonce ) ;
253- } ;
254- validate_attach_renderer_nonce ( expected_nonce) ?;
255- let ( nonce_len, nonce_offset) = read_7bit_encoded_usize ( rest) ?;
256- let nonce_end = nonce_offset. checked_add ( nonce_len) . ok_or_else ( || {
257- AttachConnectionError :: TruncatedQueueName {
258- expected : nonce_len,
259- remaining : rest. len ( ) . saturating_sub ( nonce_offset) ,
260- }
261- } ) ?;
262- if nonce_end > rest. len ( ) {
263- return Err ( AttachConnectionError :: TruncatedQueueName {
264- expected : nonce_len,
265- remaining : rest. len ( ) . saturating_sub ( nonce_offset) ,
266- } ) ;
267- }
268- if & rest[ nonce_offset..nonce_end] != expected_nonce {
269- return Err ( AttachConnectionError :: NonceMismatch ) ;
270- }
271- parse_attach_renderer_legacy_payload ( & rest[ nonce_end..] )
272- }
273-
274- /// Parses the queue portion of the host attach datagram encoded by `.NET BinaryWriter`.
275- fn parse_attach_renderer_legacy_payload (
276- packet : & [ u8 ] ,
277- ) -> Result < ConnectionParams , AttachConnectionError > {
180+ /// Parses the host attach datagram encoded by `.NET BinaryWriter`.
181+ fn parse_attach_renderer_packet ( packet : & [ u8 ] ) -> Result < ConnectionParams , AttachConnectionError > {
278182 let ( queue_name_len, queue_name_offset) = read_7bit_encoded_usize ( packet) ?;
279183 let Some ( queue_name_end) = queue_name_offset. checked_add ( queue_name_len) else {
280184 return Err ( AttachConnectionError :: TruncatedQueueName {
@@ -424,29 +328,14 @@ pub fn publisher_queue_name(base: &str, channel: &str) -> String {
424328mod tests {
425329 use super :: * ;
426330
427- const TEST_NONCE : & [ u8 ] = b"0123456789abcdef" ;
428-
429331 fn attach_packet ( queue_name : & str , queue_capacity : i64 ) -> Vec < u8 > {
430- v2_packet ( & legacy_attach_packet ( queue_name, queue_capacity) )
431- }
432-
433- fn legacy_attach_packet ( queue_name : & str , queue_capacity : i64 ) -> Vec < u8 > {
434332 let mut packet = Vec :: new ( ) ;
435333 write_7bit_encoded_usize ( queue_name. len ( ) , & mut packet) ;
436334 packet. extend_from_slice ( queue_name. as_bytes ( ) ) ;
437335 packet. extend_from_slice ( & queue_capacity. to_le_bytes ( ) ) ;
438336 packet
439337 }
440338
441- fn v2_packet ( legacy_payload : & [ u8 ] ) -> Vec < u8 > {
442- let mut packet = Vec :: new ( ) ;
443- packet. extend_from_slice ( ATTACH_RENDERER_V2_MAGIC ) ;
444- write_7bit_encoded_usize ( TEST_NONCE . len ( ) , & mut packet) ;
445- packet. extend_from_slice ( TEST_NONCE ) ;
446- packet. extend_from_slice ( legacy_payload) ;
447- packet
448- }
449-
450339 fn write_7bit_encoded_usize ( mut value : usize , packet : & mut Vec < u8 > ) {
451340 while value >= usize:: from ( SEVEN_BIT_CONTINUATION ) {
452341 packet. push ( ( value as u8 & SEVEN_BIT_VALUE_MASK ) | SEVEN_BIT_CONTINUATION ) ;
@@ -470,13 +359,10 @@ mod tests {
470359 }
471360
472361 #[ test]
473- fn parse_attach_renderer_packet_accepts_authenticated_binary_writer_payload ( ) {
362+ fn parse_attach_renderer_packet_accepts_binary_writer_payload ( ) {
474363 assert_eq ! (
475- parse_attach_renderer_packet(
476- & attach_packet( "RenderideQueue" , 8_388_608 ) ,
477- Some ( TEST_NONCE ) ,
478- )
479- . expect( "attach packet should parse" ) ,
364+ parse_attach_renderer_packet( & attach_packet( "RenderideQueue" , 8_388_608 ) )
365+ . expect( "attach packet should parse" ) ,
480366 ConnectionParams {
481367 queue_name: "RenderideQueue" . into( ) ,
482368 queue_capacity: 8_388_608 ,
@@ -488,7 +374,7 @@ mod tests {
488374 fn parse_attach_renderer_packet_accepts_multibyte_string_length ( ) {
489375 let queue_name = "q" . repeat ( 130 ) ;
490376 assert_eq ! (
491- parse_attach_renderer_packet( & attach_packet( & queue_name, 4096 ) , Some ( TEST_NONCE ) )
377+ parse_attach_renderer_packet( & attach_packet( & queue_name, 4096 ) )
492378 . expect( "attach packet should parse" ) ,
493379 ConnectionParams {
494380 queue_name,
@@ -497,53 +383,10 @@ mod tests {
497383 ) ;
498384 }
499385
500- #[ test]
501- fn parse_attach_renderer_packet_rejects_legacy_payload_when_nonce_is_configured ( ) {
502- let error = parse_attach_renderer_packet (
503- & legacy_attach_packet ( "RenderideQueue" , 8_388_608 ) ,
504- Some ( TEST_NONCE ) ,
505- )
506- . expect_err ( "legacy attach packet should be rejected" ) ;
507- assert ! ( matches!( error, AttachConnectionError :: MissingV2Magic ) ) ;
508- }
509-
510- #[ test]
511- fn parse_attach_renderer_packet_accepts_legacy_payload_when_nonce_is_absent ( ) {
512- assert_eq ! (
513- parse_attach_renderer_packet( & legacy_attach_packet( "RenderideQueue" , 8_388_608 ) , None , )
514- . expect( "legacy attach packet should parse" ) ,
515- ConnectionParams {
516- queue_name: "RenderideQueue" . into( ) ,
517- queue_capacity: 8_388_608 ,
518- }
519- ) ;
520- }
521-
522- #[ test]
523- fn parse_attach_renderer_packet_rejects_v2_payload_when_nonce_is_absent ( ) {
524- let error = parse_attach_renderer_packet ( & attach_packet ( "RenderideQueue" , 8_388_608 ) , None )
525- . expect_err ( "v2 attach packet without expected nonce should be rejected" ) ;
526- assert ! ( matches!( error, AttachConnectionError :: MissingNonce ) ) ;
527- }
528-
529- #[ test]
530- fn parse_attach_renderer_packet_rejects_nonce_mismatch ( ) {
531- let mut wrong_nonce = TEST_NONCE . to_vec ( ) ;
532- wrong_nonce[ 0 ] ^= 0xff ;
533-
534- let error = parse_attach_renderer_packet (
535- & attach_packet ( "RenderideQueue" , 8_388_608 ) ,
536- Some ( & wrong_nonce) ,
537- )
538- . expect_err ( "wrong nonce should be rejected" ) ;
539- assert ! ( matches!( error, AttachConnectionError :: NonceMismatch ) ) ;
540- }
541-
542386 #[ test]
543387 fn parse_attach_renderer_packet_rejects_truncated_string_length ( ) {
544- let error =
545- parse_attach_renderer_packet ( & v2_packet ( & [ SEVEN_BIT_CONTINUATION ] ) , Some ( TEST_NONCE ) )
546- . expect_err ( "length prefix should be incomplete" ) ;
388+ let error = parse_attach_renderer_packet ( & [ SEVEN_BIT_CONTINUATION ] )
389+ . expect_err ( "length prefix should be incomplete" ) ;
547390 assert ! ( matches!(
548391 error,
549392 AttachConnectionError :: TruncatedStringLength
@@ -552,11 +395,8 @@ mod tests {
552395
553396 #[ test]
554397 fn parse_attach_renderer_packet_rejects_malformed_string_length ( ) {
555- let error = parse_attach_renderer_packet (
556- & v2_packet ( & [ 0xff , 0xff , 0xff , 0xff , 0x08 ] ) ,
557- Some ( TEST_NONCE ) ,
558- )
559- . expect_err ( "length prefix should be malformed" ) ;
398+ let error = parse_attach_renderer_packet ( & [ 0xff , 0xff , 0xff , 0xff , 0x08 ] )
399+ . expect_err ( "length prefix should be malformed" ) ;
560400 assert ! ( matches!(
561401 error,
562402 AttachConnectionError :: MalformedStringLength
@@ -565,8 +405,8 @@ mod tests {
565405
566406 #[ test]
567407 fn parse_attach_renderer_packet_rejects_truncated_queue_name ( ) {
568- let error = parse_attach_renderer_packet ( & v2_packet ( & [ 4 , b'n' ] ) , Some ( TEST_NONCE ) )
569- . expect_err ( "queue name should be incomplete" ) ;
408+ let error =
409+ parse_attach_renderer_packet ( & [ 4 , b'n' ] ) . expect_err ( "queue name should be incomplete" ) ;
570410 assert ! ( matches!(
571411 error,
572412 AttachConnectionError :: TruncatedQueueName {
@@ -581,7 +421,7 @@ mod tests {
581421 let mut packet = vec ! [ 1 , 0xff ] ;
582422 packet. extend_from_slice ( & 4096_i64 . to_le_bytes ( ) ) ;
583423
584- let error = parse_attach_renderer_packet ( & v2_packet ( & packet) , Some ( TEST_NONCE ) )
424+ let error = parse_attach_renderer_packet ( & packet)
585425 . expect_err ( "queue name should reject invalid UTF-8" ) ;
586426 assert ! ( matches!(
587427 error,
@@ -591,11 +431,8 @@ mod tests {
591431
592432 #[ test]
593433 fn parse_attach_renderer_packet_rejects_truncated_queue_capacity ( ) {
594- let error = parse_attach_renderer_packet (
595- & v2_packet ( & [ 4 , b'n' , b'a' , b'm' , b'e' ] ) ,
596- Some ( TEST_NONCE ) ,
597- )
598- . expect_err ( "queue capacity should be incomplete" ) ;
434+ let error = parse_attach_renderer_packet ( & [ 4 , b'n' , b'a' , b'm' , b'e' ] )
435+ . expect_err ( "queue capacity should be incomplete" ) ;
599436 assert ! ( matches!(
600437 error,
601438 AttachConnectionError :: TruncatedQueueCapacity { remaining: 0 }
@@ -604,14 +441,14 @@ mod tests {
604441
605442 #[ test]
606443 fn parse_attach_renderer_packet_rejects_non_positive_queue_capacity ( ) {
607- let zero = parse_attach_renderer_packet ( & attach_packet ( "queue" , 0 ) , Some ( TEST_NONCE ) )
444+ let zero = parse_attach_renderer_packet ( & attach_packet ( "queue" , 0 ) )
608445 . expect_err ( "zero capacity should be invalid" ) ;
609446 assert ! ( matches!(
610447 zero,
611448 AttachConnectionError :: InvalidQueueCapacity { queue_capacity: 0 }
612449 ) ) ;
613450
614- let negative = parse_attach_renderer_packet ( & attach_packet ( "queue" , -1 ) , Some ( TEST_NONCE ) )
451+ let negative = parse_attach_renderer_packet ( & attach_packet ( "queue" , -1 ) )
615452 . expect_err ( "negative capacity should be invalid" ) ;
616453 assert ! ( matches!(
617454 negative,
@@ -621,10 +458,10 @@ mod tests {
621458
622459 #[ test]
623460 fn parse_attach_renderer_packet_rejects_oversized_queue_capacity ( ) {
624- let error = parse_attach_renderer_packet (
625- & attach_packet ( "queue" , interprocess :: QueueOptions :: MAX_CAPACITY + 8 ) ,
626- Some ( TEST_NONCE ) ,
627- )
461+ let error = parse_attach_renderer_packet ( & attach_packet (
462+ "queue" ,
463+ interprocess :: QueueOptions :: MAX_CAPACITY + 8 ,
464+ ) )
628465 . expect_err ( "oversized capacity should be invalid" ) ;
629466 assert ! ( matches!(
630467 error,
0 commit comments