alksocks 0.3.2

SOCKS5 (RFC 1928) proxy protocol over alkcall channels: targeted-forked fast-socks5 typestate core plus producer/consumer sessions. Producer/consumer protocol crate.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
//! The UDP front door's integration tests (feature `local`): the POC
//! #2 test-8 shape end to end: a real UDP echo target, the producer
//! with `local::udp_egress()`, the door's relay socket, a vanilla
//! RFC-header'd datagram in → the echo back RFC-header'd (the RFC
//! codec boundary pinned: the in-band wire stays `{addr, data}`
//! frames). FRAG ≠ 0 refused (dropped, association healthy); the
//! empty-datagram invariant through the door (F-2); the idle bound
//! closes an idle association; a fresh association succeeds after
//! teardown.
#![cfg(feature = "local")]

mod harness;

fn init_trace() {
    let _ = tracing_subscriber::fmt()
        .with_max_level(tracing::level_filters::LevelFilter::DEBUG)
        .with_test_writer()
        .try_init();
}

use std::net::SocketAddr;
use std::sync::Arc;
use std::time::Duration;

use tokio::net::UdpSocket;
use tokio::time::timeout;

use alksocks::UdpFrontDoor;

use harness::echo_dial;

const BOUND: Duration = Duration::from_secs(10);

/// A UDP echo server on a real kernel socket; returns its address
/// (the vanilla client's datagram target, the POC #2 shape).
async fn udp_echo_server() -> SocketAddr {
    let sock = UdpSocket::bind(("127.0.0.1", 0))
        .await
        .expect("bind udp echo");
    let addr = sock.local_addr().expect("addr");
    tokio::spawn(async move {
        let mut buf = vec![0u8; 65535];
        loop {
            let Ok((n, peer)) = sock.recv_from(&mut buf).await else {
                return;
            };
            if sock.send_to(&buf[..n], peer).await.is_err() {
                return;
            }
        }
    });
    addr
}

/// Build an RFC-header'd datagram (the vanilla client's sendto form;
/// the codec appears at the door boundary, so the test hand-rolls the
/// same header: RSV(2) FRAG(1) ATYP(1) addr port).
fn rfc_datagram(target: SocketAddr, payload: &[u8]) -> Vec<u8> {
    let SocketAddr::V4(v4) = target else {
        panic!("v4 targets only");
    };
    let mut dg = vec![0u8, 0, 0, 0x01];
    dg.extend_from_slice(&v4.ip().octets());
    dg.extend_from_slice(&v4.port().to_be_bytes());
    dg.extend_from_slice(payload);
    dg
}

/// Parse an RFC-header'd datagram back → (addr, payload).
fn parse_rfc_datagram(wire: &[u8]) -> (SocketAddr, &[u8]) {
    assert_eq!(&wire[..2], &[0, 0], "RSV zero");
    assert_eq!(wire[3], 0x01, "v4 ATYP");
    let ip = std::net::Ipv4Addr::new(wire[4], wire[5], wire[6], wire[7]);
    let port = u16::from_be_bytes([wire[8], wire[9]]);
    (SocketAddr::from((ip, port)), &wire[10..])
}

/// The happy path (the POC #2 test-8 shape, end to end): the door's
/// relay socket ← a vanilla RFC-header'd datagram → decoded at the
/// door's codec boundary → `{addr, data}` in-band → the producer's
/// stage → the real UDP echo target → back in-band → RFC-header'd →
/// the client's source address. The empty-datagram invariant rides
/// the same boundary (F-2: zero-length payload round-trips, never
/// EOF), and the in-band codec boundary is pinned (the door's relay
/// carries only RFC-header'd datagrams; the in-band wire carries only
/// `{addr, data}` frames: the round-trip through the real echo
/// target proves the two vocabularies never mixed).
#[tokio::test]
async fn udp_door_vanilla_client_round_trip_and_empty_datagram() {
    init_trace();
    let echo_addr = udp_echo_server().await;
    let topo = harness::wire_consumer_side_with(
        echo_dial(),
        Some(alksocks::udp_egress()),
        None,
        Some(harness::consumer_identity()),
    )
    .await;

    let relay = UdpSocket::bind("127.0.0.1:0").await.expect("bind relay");
    let relay_addr = relay.local_addr().expect("relay addr");
    let client = UdpSocket::bind("127.0.0.1:0").await.expect("client socket");
    let door = UdpFrontDoor::builder()
        .bind(relay_addr)
        .build()
        .expect("the door builds");
    let _serve = tokio::spawn({
        let client = Arc::clone(&topo.consumer);
        async move { door.serve_on(relay, client).await.expect("the door serves") }
    });

    // Pre: a normal datagram round-trips.
    client
        .send_to(&rfc_datagram(echo_addr, b"pre"), relay_addr)
        .await
        .expect("vanilla sendto the relay");
    let mut rx = vec![0u8; 65535];
    let (n, from) = timeout(BOUND, client.recv_from(&mut rx))
        .await
        .expect("reply within bound")
        .expect("recv");
    assert_eq!(from, relay_addr, "the reply comes from the relay socket");
    let (addr, payload) = parse_rfc_datagram(&rx[..n]);
    assert_eq!(addr, echo_addr, "the echo reports the target");
    assert_eq!(payload, b"pre");

    // The empty datagram (F-2): a zero-length payload round-trips,
    // never EOF: the association stays healthy after it.
    client
        .send_to(&rfc_datagram(echo_addr, b""), relay_addr)
        .await
        .expect("send the empty datagram");
    let (n, _) = timeout(BOUND, client.recv_from(&mut rx))
        .await
        .expect("empty-datagram reply within bound")
        .expect("recv");
    let (addr, payload) = parse_rfc_datagram(&rx[..n]);
    assert_eq!(addr, echo_addr);
    assert!(
        payload.is_empty(),
        "the empty datagram round-trips (never EOF)"
    );

    // Post: the association survived; another datagram round-trips.
    client
        .send_to(&rfc_datagram(echo_addr, b"post"), relay_addr)
        .await
        .expect("send post");
    let (n, _) = timeout(BOUND, client.recv_from(&mut rx))
        .await
        .expect("post reply within bound")
        .expect("recv");
    let (_, payload) = parse_rfc_datagram(&rx[..n]);
    assert_eq!(payload, b"post");

    // The in-band vocabulary pin: the association's adopted channel
    // exists (the door opened it in-band via AssociateSession) and the
    // producer's stage saw the real echo target (the datagrams were
    // carried as `{addr, data}` frames (the echo server, which speaks
    // only raw kernel datagrams, answered), never RFC-header'd bytes.
    assert!(
        topo.consumer
            .manager()
            .channel_ids()
            .iter()
            .any(|&id| id != 0),
        "the door's association rode an in-band channel"
    );
}

/// The reader-state pin through the door's bridge (review 003 R-1,
/// the POC #2 finding carried to the doors): two replies arriving
/// back-to-back (the doubled echo: both frames ride the producer's
/// frame writer; the door's channel read may batch them into one
/// chunk) both reach the vanilla client. A bridge that re-created
/// its decoder per read lost the second datagram.
#[tokio::test]
async fn batched_in_band_replies_both_reach_the_vanilla_client() {
    let echo_addr = udp_echo_server().await;
    let topo = harness::wire_consumer_side_with(
        echo_dial(),
        Some(harness::doubled_echo_egress_factory()),
        None,
        Some(harness::consumer_identity()),
    )
    .await;

    let relay = UdpSocket::bind("127.0.0.1:0").await.expect("bind relay");
    let relay_addr = relay.local_addr().expect("relay addr");
    let client = UdpSocket::bind("127.0.0.1:0").await.expect("client socket");
    let door = UdpFrontDoor::builder()
        .bind(relay_addr)
        .build()
        .expect("the door builds");
    let _serve = tokio::spawn({
        let client = Arc::clone(&topo.consumer);
        async move { door.serve_on(relay, client).await.expect("the door serves") }
    });

    // One datagram in → two echo datagrams out (both from the relay
    // socket, both carrying the target as their source address; the
    // bridge's pending queue drained in order, none lost).
    client
        .send_to(&rfc_datagram(echo_addr, b"once"), relay_addr)
        .await
        .expect("send");
    let mut rx = vec![0u8; 65535];
    for _ in 0..2 {
        let (n, from) = timeout(BOUND, client.recv_from(&mut rx))
            .await
            .expect("reply within bound")
            .expect("recv");
        assert_eq!(from, relay_addr, "the reply comes from the relay socket");
        let (addr, payload) = parse_rfc_datagram(&rx[..n]);
        assert_eq!(addr, echo_addr);
        assert_eq!(payload, b"once");
    }

    // No third reply: exactly the two echoes arrived (the burst was
    // queued, not duplicated).
    let mut probe = vec![0u8; 65535];
    assert!(
        timeout(Duration::from_millis(300), client.recv_from(&mut probe))
            .await
            .is_err(),
        "exactly two replies arrived"
    );
}

/// FRAG ≠ 0 is refused at the door (the v1 posture): the fragment is
/// dropped (nothing is egressed), and the association stays healthy
/// (a following normal datagram round-trips).
#[tokio::test]
async fn frag_nonzero_refused_and_association_stays_healthy() {
    let echo_addr = udp_echo_server().await;
    let topo = harness::wire_consumer_side_with(
        echo_dial(),
        Some(alksocks::udp_egress()),
        None,
        Some(harness::consumer_identity()),
    )
    .await;

    let relay = UdpSocket::bind("127.0.0.1:0").await.expect("bind relay");
    let relay_addr = relay.local_addr().expect("relay addr");
    let client = UdpSocket::bind("127.0.0.1:0").await.expect("client socket");
    let door = UdpFrontDoor::builder()
        .bind(relay_addr)
        .build()
        .expect("the door builds");
    let _serve = tokio::spawn({
        let client = Arc::clone(&topo.consumer);
        async move { door.serve_on(relay, client).await.expect("the door serves") }
    });

    // A FRAG=1 datagram: dropped at the door's codec boundary (no
    // echo comes back, because the datagram never went in-band).
    let SocketAddr::V4(v4) = echo_addr else {
        panic!("v4 target")
    };
    let mut frag_dg = vec![0u8, 0, 1, 0x01];
    frag_dg.extend_from_slice(&v4.ip().octets());
    frag_dg.extend_from_slice(&v4.port().to_be_bytes());
    frag_dg.extend_from_slice(b"fragmented");
    client
        .send_to(&frag_dg, relay_addr)
        .await
        .expect("send frag");

    // A normal datagram right after: the FRAG drop left the door
    // serving: the association is healthy.
    client
        .send_to(&rfc_datagram(echo_addr, b"healthy"), relay_addr)
        .await
        .expect("send after frag");
    let mut rx = vec![0u8; 65535];
    let (n, _) = timeout(BOUND, client.recv_from(&mut rx))
        .await
        .expect("reply within bound")
        .expect("recv");
    let (_, payload) = parse_rfc_datagram(&rx[..n]);
    assert_eq!(
        payload, b"healthy",
        "the association survived the FRAG drop"
    );

    // And the fragment's payload never echoed: only one reply arrived
    // (the recv above consumed it; the next recv times out).
    let mut probe = vec![0u8; 65535];
    assert!(
        timeout(Duration::from_millis(300), client.recv_from(&mut probe))
            .await
            .is_err(),
        "the FRAG ≠ 0 datagram was dropped (never egressed)"
    );
}

/// The client idle bound (ADR-014's door-side defense, constructor
/// config): a client that sends no datagrams within the window gets
/// its association closed door-side: the door's task ends, the
/// association's channel is reaped (association lifetime = channel
/// lifetime, ADR-003), and a fresh association succeeds after the
/// teardown (the connection is healthy).
#[tokio::test]
async fn idle_bound_closes_an_idle_association_and_a_fresh_one_succeeds() {
    let echo_addr = udp_echo_server().await;
    let topo = harness::wire_consumer_side_with(
        echo_dial(),
        Some(alksocks::udp_egress()),
        None,
        Some(harness::consumer_identity()),
    )
    .await;

    // First association: never sends, so the idle bound fires within
    // (window + slack) and the door's task ends.
    let relay = UdpSocket::bind("127.0.0.1:0").await.expect("bind relay");
    let door = UdpFrontDoor::builder()
        .bind(relay.local_addr().unwrap())
        .idle(Duration::from_millis(300))
        .build()
        .expect("the door builds");
    let serve = tokio::spawn({
        let client = Arc::clone(&topo.consumer);
        async move { door.serve_on(relay, client).await.expect("the door serves") }
    });

    let started = std::time::Instant::now();
    timeout(Duration::from_secs(3), serve)
        .await
        .expect("the door's task ended")
        .expect("serve returns cleanly on the idle exit");
    let elapsed = started.elapsed();
    assert!(
        elapsed >= Duration::from_millis(250),
        "the door waited the window before closing: {elapsed:?}"
    );

    // The association's channel was torn down with the door.
    tokio::time::sleep(Duration::from_millis(100)).await;
    assert!(
        topo.consumer
            .manager()
            .channel_ids()
            .iter()
            .all(|&id| id == 0),
        "the idle teardown reaped the association's channel"
    );

    // A fresh association succeeds after the teardown (the connection
    // is healthy, the POC's strongest observable).
    let relay2 = UdpSocket::bind("127.0.0.1:0").await.expect("bind relay 2");
    let relay2_addr = relay2.local_addr().unwrap();
    let door2 = UdpFrontDoor::builder()
        .bind(relay2_addr)
        .build()
        .expect("the door builds");
    let _serve2 = tokio::spawn({
        let client = Arc::clone(&topo.consumer);
        async move {
            door2
                .serve_on(relay2, client)
                .await
                .expect("the fresh door serves")
        }
    });
    let client = UdpSocket::bind("127.0.0.1:0").await.expect("client socket");
    client
        .send_to(&rfc_datagram(echo_addr, b"fresh"), relay2_addr)
        .await
        .expect("send through the fresh door");
    let mut rx = vec![0u8; 65535];
    let (n, _) = timeout(BOUND, client.recv_from(&mut rx))
        .await
        .expect("fresh reply within bound")
        .expect("recv");
    let (addr, payload) = parse_rfc_datagram(&rx[..n]);
    assert_eq!(addr, echo_addr);
    assert_eq!(payload, b"fresh");
}

/// A fresh association succeeds after teardown, driven through the
/// same relay-port shape as the happy path (the idle test's follow-up,
/// pinned on its own so the "connection healthy" observable stands
/// alone).
#[tokio::test]
async fn fresh_association_succeeds_after_teardown() {
    let echo_addr = udp_echo_server().await;
    let topo = harness::wire_consumer_side_with(
        echo_dial(),
        Some(alksocks::udp_egress()),
        None,
        Some(harness::consumer_identity()),
    )
    .await;

    // First association: one datagram, then the client drops the
    // socket (the door's association ends with the idle bound).
    let relay = UdpSocket::bind("127.0.0.1:0").await.expect("bind relay");
    let relay_addr = relay.local_addr().expect("relay addr");
    let door = UdpFrontDoor::builder()
        .bind(relay_addr)
        .idle(Duration::from_millis(200))
        .build()
        .expect("the door builds");
    let serve = tokio::spawn({
        let client = Arc::clone(&topo.consumer);
        async move { door.serve_on(relay, client).await.expect("the door serves") }
    });
    let vanilla = UdpSocket::bind("127.0.0.1:0")
        .await
        .expect("vanilla socket");
    vanilla
        .send_to(&rfc_datagram(echo_addr, b"first"), relay_addr)
        .await
        .expect("send first");
    let mut rx = vec![0u8; 65535];
    let (n, _) = timeout(BOUND, vanilla.recv_from(&mut rx))
        .await
        .expect("first reply within bound")
        .expect("recv");
    assert_eq!(parse_rfc_datagram(&rx[..n]).1, b"first");
    timeout(Duration::from_secs(3), serve)
        .await
        .expect("the first association ended (idle bound)")
        .expect("clean exit");

    // A fresh association on the same topology succeeds end to end.
    let relay2 = UdpSocket::bind("127.0.0.1:0").await.expect("bind relay 2");
    let relay2_addr = relay2.local_addr().expect("relay2 addr");
    let door2 = UdpFrontDoor::builder()
        .bind(relay2_addr)
        .build()
        .expect("the door builds");
    let serve2 = tokio::spawn({
        let client = Arc::clone(&topo.consumer);
        async move {
            door2
                .serve_on(relay2, client)
                .await
                .expect("the fresh door serves")
        }
    });
    let client = UdpSocket::bind("127.0.0.1:0").await.expect("client socket");
    client
        .send_to(&rfc_datagram(echo_addr, b"fresh"), relay2_addr)
        .await
        .expect("send through the fresh door");
    let (n, _) = timeout(BOUND, client.recv_from(&mut rx))
        .await
        .expect("fresh reply within bound")
        .expect("recv");
    let (addr, payload) = parse_rfc_datagram(&rx[..n]);
    assert_eq!(addr, echo_addr);
    assert_eq!(payload, b"fresh");
    serve2.abort();
}

/// The `serve()` wrapper (review 003 N-8: every other test drove
/// `serve_on`; the bind-then-serve wrapper round-trips too; the port is
/// configured explicitly so the vanilla client can address the
/// relay).
#[tokio::test]
async fn udp_door_serve_wrapper_round_trips() {
    init_trace();
    let echo_addr = udp_echo_server().await;
    let topo = harness::wire_consumer_side_with(
        echo_dial(),
        Some(alksocks::udp_egress()),
        None,
        Some(harness::consumer_identity()),
    )
    .await;

    // A free loopback port, probed up front (the door binds exactly
    // it, the wrapper's own bind decision).
    let probe = UdpSocket::bind("127.0.0.1:0").await.expect("probe bind");
    let relay_addr = probe.local_addr().expect("probe addr");
    drop(probe);

    let client = UdpSocket::bind("127.0.0.1:0").await.expect("client socket");
    let door = UdpFrontDoor::builder()
        .bind(relay_addr)
        .build()
        .expect("the door builds");
    let _serve = tokio::spawn({
        let client = Arc::clone(&topo.consumer);
        async move { door.serve(client).await.expect("the door serves") }
    });

    client
        .send_to(&rfc_datagram(echo_addr, b"wrapped"), relay_addr)
        .await
        .expect("vanilla sendto the relay");
    let mut rx = vec![0u8; 65535];
    let (n, from) = timeout(BOUND, client.recv_from(&mut rx))
        .await
        .expect("reply within bound")
        .expect("recv");
    assert_eq!(from, relay_addr, "the reply comes from the wrapper's bind");
    let (_, payload) = parse_rfc_datagram(&rx[..n]);
    assert_eq!(payload, b"wrapped");
}

/// The NAT port-rebind shape (OQ-SK2-09's option-2 fix): the client's
/// source IP pins on the first datagram, and a later datagram from the
/// same IP on a *new source port* moves the reply path (the rebind
/// keeps receiving replies. The RFC drop rule's complement: replies go
/// to the latest-seen port from the pinned IP.
#[tokio::test]
async fn nat_port_rebind_keeps_receiving_replies() {
    let echo_addr = udp_echo_server().await;
    let topo = harness::wire_consumer_side_with(
        echo_dial(),
        Some(alksocks::udp_egress()),
        None,
        Some(harness::consumer_identity()),
    )
    .await;

    let relay = UdpSocket::bind("127.0.0.1:0").await.expect("bind relay");
    let relay_addr = relay.local_addr().expect("relay addr");
    let door = UdpFrontDoor::builder()
        .bind(relay_addr)
        .build()
        .expect("the door builds");
    let _serve = tokio::spawn({
        let client = Arc::clone(&topo.consumer);
        async move { door.serve_on(relay, client).await.expect("the door serves") }
    });

    // Association born on socket A (its source port pins the reply
    // path's IP; the port rides the latest-seen shape).
    let client_a = UdpSocket::bind("127.0.0.1:0").await.expect("client A");
    client_a
        .send_to(&rfc_datagram(echo_addr, b"before"), relay_addr)
        .await
        .expect("send from A");
    let mut rx = vec![0u8; 65535];
    let (n, _) = timeout(BOUND, client_a.recv_from(&mut rx))
        .await
        .expect("reply within bound")
        .expect("recv");
    assert_eq!(parse_rfc_datagram(&rx[..n]).1, b"before");

    // The "NAT rebind": a fresh socket, same IP, new source port. The
    // datagram is accepted (same IP) and the reply goes to the *new*
    // port; the rebind keeps receiving.
    let client_b = UdpSocket::bind("127.0.0.1:0").await.expect("client B");
    client_b
        .send_to(&rfc_datagram(echo_addr, b"after"), relay_addr)
        .await
        .expect("send from B");
    let (n, _) = timeout(BOUND, client_b.recv_from(&mut rx))
        .await
        .expect("rebound reply within bound")
        .expect("recv");
    assert_eq!(parse_rfc_datagram(&rx[..n]).1, b"after");

    // A (the old port) no longer receives: the reply path followed
    // the rebind.
    let mut probe = vec![0u8; 65535];
    assert!(
        timeout(Duration::from_millis(300), client_a.recv_from(&mut probe))
            .await
            .is_err(),
        "the reply followed the rebind (the old port stopped receiving)"
    );
}

/// The RFC 1928 peer posture's drop rule (OQ-SK2-09's option-2 fix):
/// a datagram from a *different source IP* is dropped (never
/// egressed), and the association stays healthy for the pinned peer.
/// (Loopback-only IPs are used: the pinned peer keeps receiving, the
/// foreign-IP sender's datagram disappears.)
#[tokio::test]
async fn foreign_source_ip_datagrams_dropped_and_association_stays_healthy() {
    init_trace();
    let echo_addr = udp_echo_server().await;
    let topo = harness::wire_consumer_side_with(
        echo_dial(),
        Some(alksocks::udp_egress()),
        None,
        Some(harness::consumer_identity()),
    )
    .await;

    let relay = UdpSocket::bind("127.0.0.1:0").await.expect("bind relay");
    let relay_addr = relay.local_addr().expect("relay addr");
    let door = UdpFrontDoor::builder()
        .bind(relay_addr)
        .build()
        .expect("the door builds");
    let _serve = tokio::spawn({
        let client = Arc::clone(&topo.consumer);
        async move { door.serve_on(relay, client).await.expect("the door serves") }
    });

    // The real client pins the peer on loopback (127.0.0.1).
    let client = UdpSocket::bind("127.0.0.1:0").await.expect("client");
    client
        .send_to(&rfc_datagram(echo_addr, b"pinned"), relay_addr)
        .await
        .expect("send pinned");
    let mut rx = vec![0u8; 65535];
    let (n, _) = timeout(BOUND, client.recv_from(&mut rx))
        .await
        .expect("reply within bound")
        .expect("recv");
    assert_eq!(parse_rfc_datagram(&rx[..n]).1, b"pinned");

    // A "foreign-IP" sender: 127.0.0.2 (loopback, a different IP,
    // bindable without privileges). Its datagram is dropped at the
    // door's peer gate: no echo comes back to it, and nothing is
    // egressed to the echo target on its behalf.
    let foreign = UdpSocket::bind("127.0.0.2:0").await.expect("foreign bind");
    foreign
        .send_to(&rfc_datagram(echo_addr, b"hijack"), relay_addr)
        .await
        .expect("send foreign");
    let mut probe = vec![0u8; 65535];
    assert!(
        timeout(Duration::from_millis(400), foreign.recv_from(&mut probe))
            .await
            .is_err(),
        "the foreign-IP datagram was dropped (no reply to the spoofer)"
    );

    // The pinned peer is unaffected: its next datagram round-trips
    // (the drop left the association healthy; the gate never evicts).
    client
        .send_to(&rfc_datagram(echo_addr, b"still"), relay_addr)
        .await
        .expect("send still");
    let (n, _) = timeout(BOUND, client.recv_from(&mut rx))
        .await
        .expect("still-reply within bound")
        .expect("recv");
    assert_eq!(
        parse_rfc_datagram(&rx[..n]).1,
        b"still",
        "the association survived the foreign-IP drop"
    );
}