1 use super::*;
2 use crate::vnet::chunk::ChunkUdp;
3 use std::net::SocketAddr;
4 use std::str::FromStr;
5
6 // oic: outbound internal chunk
7 // oec: outbound external chunk
8 // iic: inbound internal chunk
9 // iec: inbound external chunk
10
11 const DEMO_IP: &str = "1.2.3.4";
12
13 #[test]
test_nat_type_default() -> Result<()>14 fn test_nat_type_default() -> Result<()> {
15 let nat = NetworkAddressTranslator::new(NatConfig {
16 mapped_ips: vec![IpAddr::from_str(DEMO_IP)?],
17 ..Default::default()
18 })?;
19
20 assert_eq!(
21 nat.nat_type.mapping_behavior,
22 EndpointDependencyType::EndpointIndependent,
23 "should match"
24 );
25 assert_eq!(
26 nat.nat_type.filtering_behavior,
27 EndpointDependencyType::EndpointIndependent,
28 "should match"
29 );
30 assert!(!nat.nat_type.hair_pining, "should be false");
31 assert!(!nat.nat_type.port_preservation, "should be false");
32 assert_eq!(
33 nat.nat_type.mapping_life_time, DEFAULT_NAT_MAPPING_LIFE_TIME,
34 "should be false"
35 );
36
37 Ok(())
38 }
39
40 #[tokio::test]
test_nat_mapping_behavior_full_cone_nat() -> Result<()>41 async fn test_nat_mapping_behavior_full_cone_nat() -> Result<()> {
42 let nat = NetworkAddressTranslator::new(NatConfig {
43 nat_type: NatType {
44 mapping_behavior: EndpointDependencyType::EndpointIndependent,
45 filtering_behavior: EndpointDependencyType::EndpointIndependent,
46 hair_pining: false,
47 mapping_life_time: Duration::from_secs(30),
48 ..Default::default()
49 },
50 mapped_ips: vec![IpAddr::from_str(DEMO_IP)?],
51 ..Default::default()
52 })?;
53
54 let src = SocketAddr::from_str("192.168.0.2:1234")?;
55 let dst = SocketAddr::from_str("5.6.7.8:5678")?;
56
57 let oic = ChunkUdp::new(src, dst);
58
59 let oec = nat.translate_outbound(&oic).await?.unwrap();
60 assert_eq!(nat.outbound_map_len().await, 1, "should match");
61 assert_eq!(nat.inbound_map_len().await, 1, "should match");
62
63 log::debug!("o-original : {}", oic);
64 log::debug!("o-translated: {}", oec);
65
66 let iec = ChunkUdp::new(
67 SocketAddr::new(dst.ip(), dst.port()),
68 SocketAddr::new(oec.source_addr().ip(), oec.source_addr().port()),
69 );
70
71 log::debug!("i-original : {}", iec);
72
73 let iic = nat.translate_inbound(&iec).await?.unwrap();
74
75 log::debug!("i-translated: {}", iic);
76
77 assert_eq!(oic.source_addr(), iic.destination_addr(), "should match");
78
79 // packet with dest addr that does not exist in the mapping table
80 // will be dropped
81 let iec = ChunkUdp::new(
82 SocketAddr::new(dst.ip(), dst.port()),
83 SocketAddr::new(oec.source_addr().ip(), oec.source_addr().port() + 1),
84 );
85
86 let result = nat.translate_inbound(&iec).await;
87 assert!(result.is_err(), "should fail (dropped)");
88
89 // packet from any addr will be accepted (full-cone)
90 let iec = ChunkUdp::new(
91 SocketAddr::new(dst.ip(), 7777),
92 SocketAddr::new(oec.source_addr().ip(), oec.source_addr().port()),
93 );
94
95 let result = nat.translate_inbound(&iec).await;
96 assert!(result.is_ok(), "should succeed");
97
98 Ok(())
99 }
100
101 #[tokio::test]
test_nat_mapping_behavior_addr_restricted_cone_nat() -> Result<()>102 async fn test_nat_mapping_behavior_addr_restricted_cone_nat() -> Result<()> {
103 let nat = NetworkAddressTranslator::new(NatConfig {
104 nat_type: NatType {
105 mapping_behavior: EndpointDependencyType::EndpointIndependent,
106 filtering_behavior: EndpointDependencyType::EndpointAddrDependent,
107 hair_pining: false,
108 mapping_life_time: Duration::from_secs(30),
109 ..Default::default()
110 },
111 mapped_ips: vec![IpAddr::from_str(DEMO_IP)?],
112 ..Default::default()
113 })?;
114
115 let src = SocketAddr::from_str("192.168.0.2:1234")?;
116 let dst = SocketAddr::from_str("5.6.7.8:5678")?;
117
118 let oic = ChunkUdp::new(src, dst);
119 log::debug!("o-original : {}", oic);
120
121 let oec = nat.translate_outbound(&oic).await?.unwrap();
122 assert_eq!(nat.outbound_map_len().await, 1, "should match");
123 assert_eq!(nat.inbound_map_len().await, 1, "should match");
124 log::debug!("o-translated: {}", oec);
125
126 // sending different (IP: 5.6.7.9) won't create a new mapping
127 let oic2 = ChunkUdp::new(
128 SocketAddr::from_str("192.168.0.2:1234")?,
129 SocketAddr::from_str("5.6.7.9:9000")?,
130 );
131 let oec2 = nat.translate_outbound(&oic2).await?.unwrap();
132 assert_eq!(nat.outbound_map_len().await, 1, "should match");
133 assert_eq!(nat.inbound_map_len().await, 1, "should match");
134 log::debug!("o-translated: {}", oec2);
135
136 let iec = ChunkUdp::new(
137 SocketAddr::new(dst.ip(), dst.port()),
138 SocketAddr::new(oec.source_addr().ip(), oec.source_addr().port()),
139 );
140
141 log::debug!("i-original : {}", iec);
142
143 let iic = nat.translate_inbound(&iec).await?.unwrap();
144
145 log::debug!("i-translated: {}", iic);
146
147 assert_eq!(oic.source_addr(), iic.destination_addr(), "should match");
148
149 // packet with dest addr that does not exist in the mapping table
150 // will be dropped
151 let iec = ChunkUdp::new(
152 SocketAddr::new(dst.ip(), dst.port()),
153 SocketAddr::new(oec.source_addr().ip(), oec.source_addr().port() + 1),
154 );
155
156 let result = nat.translate_inbound(&iec).await;
157 assert!(result.is_err(), "should fail (dropped)");
158
159 // packet from any port will be accepted (restricted-cone)
160 let iec = ChunkUdp::new(
161 SocketAddr::new(dst.ip(), 7777),
162 SocketAddr::new(oec.source_addr().ip(), oec.source_addr().port()),
163 );
164
165 let result = nat.translate_inbound(&iec).await;
166 assert!(result.is_ok(), "should succeed");
167
168 // packet from different addr will be droped (restricted-cone)
169 let iec = ChunkUdp::new(
170 SocketAddr::from_str(&format!("{}:{}", "6.6.6.6", dst.port()))?,
171 SocketAddr::new(oec.source_addr().ip(), oec.source_addr().port()),
172 );
173
174 let result = nat.translate_inbound(&iec).await;
175 assert!(result.is_err(), "should fail (dropped)");
176
177 Ok(())
178 }
179
180 #[tokio::test]
test_nat_mapping_behavior_port_restricted_cone_nat() -> Result<()>181 async fn test_nat_mapping_behavior_port_restricted_cone_nat() -> Result<()> {
182 let nat = NetworkAddressTranslator::new(NatConfig {
183 nat_type: NatType {
184 mapping_behavior: EndpointDependencyType::EndpointIndependent,
185 filtering_behavior: EndpointDependencyType::EndpointAddrPortDependent,
186 hair_pining: false,
187 mapping_life_time: Duration::from_secs(30),
188 ..Default::default()
189 },
190 mapped_ips: vec![IpAddr::from_str(DEMO_IP)?],
191 ..Default::default()
192 })?;
193
194 let src = SocketAddr::from_str("192.168.0.2:1234")?;
195 let dst = SocketAddr::from_str("5.6.7.8:5678")?;
196
197 let oic = ChunkUdp::new(src, dst);
198 log::debug!("o-original : {}", oic);
199
200 let oec = nat.translate_outbound(&oic).await?.unwrap();
201 assert_eq!(nat.outbound_map_len().await, 1, "should match");
202 assert_eq!(nat.inbound_map_len().await, 1, "should match");
203 log::debug!("o-translated: {}", oec);
204
205 // sending different (IP: 5.6.7.9) won't create a new mapping
206 let oic2 = ChunkUdp::new(
207 SocketAddr::from_str("192.168.0.2:1234")?,
208 SocketAddr::from_str("5.6.7.9:9000")?,
209 );
210 let oec2 = nat.translate_outbound(&oic2).await?.unwrap();
211 assert_eq!(nat.outbound_map_len().await, 1, "should match");
212 assert_eq!(nat.inbound_map_len().await, 1, "should match");
213 log::debug!("o-translated: {}", oec2);
214
215 let iec = ChunkUdp::new(
216 SocketAddr::new(dst.ip(), dst.port()),
217 SocketAddr::new(oec.source_addr().ip(), oec.source_addr().port()),
218 );
219
220 log::debug!("i-original : {}", iec);
221
222 let iic = nat.translate_inbound(&iec).await?.unwrap();
223
224 log::debug!("i-translated: {}", iic);
225
226 assert_eq!(oic.source_addr(), iic.destination_addr(), "should match");
227
228 // packet with dest addr that does not exist in the mapping table
229 // will be dropped
230 let iec = ChunkUdp::new(
231 SocketAddr::new(dst.ip(), dst.port()),
232 SocketAddr::new(oec.source_addr().ip(), oec.source_addr().port() + 1),
233 );
234
235 let result = nat.translate_inbound(&iec).await;
236 assert!(result.is_err(), "should fail (dropped)");
237
238 // packet from different port will be dropped (port-restricted-cone)
239 let iec = ChunkUdp::new(
240 SocketAddr::new(dst.ip(), 7777),
241 SocketAddr::new(oec.source_addr().ip(), oec.source_addr().port()),
242 );
243
244 let result = nat.translate_inbound(&iec).await;
245 assert!(result.is_err(), "should fail (dropped)");
246
247 // packet from different addr will be droped (restricted-cone)
248 let iec = ChunkUdp::new(
249 SocketAddr::from_str(&format!("{}:{}", "6.6.6.6", dst.port()))?,
250 SocketAddr::new(oec.source_addr().ip(), oec.source_addr().port()),
251 );
252
253 let result = nat.translate_inbound(&iec).await;
254 assert!(result.is_err(), "should fail (dropped)");
255
256 Ok(())
257 }
258
259 #[tokio::test]
test_nat_mapping_behavior_symmetric_nat_addr_dependent_mapping() -> Result<()>260 async fn test_nat_mapping_behavior_symmetric_nat_addr_dependent_mapping() -> Result<()> {
261 let nat = NetworkAddressTranslator::new(NatConfig {
262 nat_type: NatType {
263 mapping_behavior: EndpointDependencyType::EndpointAddrDependent,
264 filtering_behavior: EndpointDependencyType::EndpointAddrDependent,
265 hair_pining: false,
266 mapping_life_time: Duration::from_secs(30),
267 ..Default::default()
268 },
269 mapped_ips: vec![IpAddr::from_str(DEMO_IP)?],
270 ..Default::default()
271 })?;
272
273 let src = SocketAddr::from_str("192.168.0.2:1234")?;
274 let dst1 = SocketAddr::from_str("5.6.7.8:5678")?;
275 let dst2 = SocketAddr::from_str("5.6.7.100:5678")?;
276 let dst3 = SocketAddr::from_str("5.6.7.8:6000")?;
277
278 let oic1 = ChunkUdp::new(src, dst1);
279 let oic2 = ChunkUdp::new(src, dst2);
280 let oic3 = ChunkUdp::new(src, dst3);
281
282 log::debug!("o-original : {}", oic1);
283 log::debug!("o-original : {}", oic2);
284 log::debug!("o-original : {}", oic3);
285
286 let oec1 = nat.translate_outbound(&oic1).await?.unwrap();
287 let oec2 = nat.translate_outbound(&oic2).await?.unwrap();
288 let oec3 = nat.translate_outbound(&oic3).await?.unwrap();
289
290 assert_eq!(nat.outbound_map_len().await, 2, "should match");
291 assert_eq!(nat.inbound_map_len().await, 2, "should match");
292
293 log::debug!("o-translated: {}", oec1);
294 log::debug!("o-translated: {}", oec2);
295 log::debug!("o-translated: {}", oec3);
296
297 assert_ne!(
298 oec1.source_addr().port(),
299 oec2.source_addr().port(),
300 "should not match"
301 );
302 assert_eq!(
303 oec1.source_addr().port(),
304 oec3.source_addr().port(),
305 "should match"
306 );
307
308 Ok(())
309 }
310
311 #[tokio::test]
test_nat_mapping_behavior_symmetric_nat_port_dependent_mapping() -> Result<()>312 async fn test_nat_mapping_behavior_symmetric_nat_port_dependent_mapping() -> Result<()> {
313 let nat = NetworkAddressTranslator::new(NatConfig {
314 nat_type: NatType {
315 mapping_behavior: EndpointDependencyType::EndpointAddrPortDependent,
316 filtering_behavior: EndpointDependencyType::EndpointAddrPortDependent,
317 hair_pining: false,
318 mapping_life_time: Duration::from_secs(30),
319 ..Default::default()
320 },
321 mapped_ips: vec![IpAddr::from_str(DEMO_IP)?],
322 ..Default::default()
323 })?;
324
325 let src = SocketAddr::from_str("192.168.0.2:1234")?;
326 let dst1 = SocketAddr::from_str("5.6.7.8:5678")?;
327 let dst2 = SocketAddr::from_str("5.6.7.100:5678")?;
328 let dst3 = SocketAddr::from_str("5.6.7.8:6000")?;
329
330 let oic1 = ChunkUdp::new(src, dst1);
331 let oic2 = ChunkUdp::new(src, dst2);
332 let oic3 = ChunkUdp::new(src, dst3);
333
334 log::debug!("o-original : {}", oic1);
335 log::debug!("o-original : {}", oic2);
336 log::debug!("o-original : {}", oic3);
337
338 let oec1 = nat.translate_outbound(&oic1).await?.unwrap();
339 let oec2 = nat.translate_outbound(&oic2).await?.unwrap();
340 let oec3 = nat.translate_outbound(&oic3).await?.unwrap();
341
342 assert_eq!(nat.outbound_map_len().await, 3, "should match");
343 assert_eq!(nat.inbound_map_len().await, 3, "should match");
344
345 log::debug!("o-translated: {}", oec1);
346 log::debug!("o-translated: {}", oec2);
347 log::debug!("o-translated: {}", oec3);
348
349 assert_ne!(
350 oec1.source_addr().port(),
351 oec2.source_addr().port(),
352 "should not match"
353 );
354 assert_ne!(
355 oec1.source_addr().port(),
356 oec3.source_addr().port(),
357 "should match"
358 );
359
360 Ok(())
361 }
362
363 #[tokio::test]
test_nat_mapping_timeout_refresh_on_outbound() -> Result<()>364 async fn test_nat_mapping_timeout_refresh_on_outbound() -> Result<()> {
365 let nat = NetworkAddressTranslator::new(NatConfig {
366 nat_type: NatType {
367 mapping_behavior: EndpointDependencyType::EndpointIndependent,
368 filtering_behavior: EndpointDependencyType::EndpointIndependent,
369 hair_pining: false,
370 mapping_life_time: Duration::from_millis(200),
371 ..Default::default()
372 },
373 mapped_ips: vec![IpAddr::from_str(DEMO_IP)?],
374 ..Default::default()
375 })?;
376
377 let src = SocketAddr::from_str("192.168.0.2:1234")?;
378 let dst = SocketAddr::from_str("5.6.7.8:5678")?;
379
380 let oic = ChunkUdp::new(src, dst);
381
382 let oec = nat.translate_outbound(&oic).await?.unwrap();
383 assert_eq!(nat.outbound_map_len().await, 1, "should match");
384 assert_eq!(nat.inbound_map_len().await, 1, "should match");
385
386 log::debug!("o-original : {}", oic);
387 log::debug!("o-translated: {}", oec);
388
389 // record mapped addr
390 let mapped = oec.source_addr().to_string();
391
392 tokio::time::sleep(Duration::from_millis(5)).await;
393
394 // refresh
395 let oec = nat.translate_outbound(&oic).await?.unwrap();
396 assert_eq!(nat.outbound_map_len().await, 1, "should match");
397 assert_eq!(nat.inbound_map_len().await, 1, "should match");
398
399 log::debug!("o-original : {}", oic);
400 log::debug!("o-translated: {}", oec);
401
402 assert_eq!(
403 mapped,
404 oec.source_addr().to_string(),
405 "mapped addr should match"
406 );
407
408 // sleep long enough for the mapping to expire
409 tokio::time::sleep(Duration::from_millis(225)).await;
410
411 // refresh after expiration
412 let oec = nat.translate_outbound(&oic).await?.unwrap();
413 assert_eq!(nat.outbound_map_len().await, 1, "should match");
414 assert_eq!(nat.inbound_map_len().await, 1, "should match");
415
416 log::debug!("o-original : {}", oic);
417 log::debug!("o-translated: {}", oec);
418
419 assert_ne!(
420 oec.source_addr().to_string(),
421 mapped,
422 "mapped addr should not match"
423 );
424
425 Ok(())
426 }
427
428 #[tokio::test]
test_nat_mapping_timeout_outbound_detects_timeout() -> Result<()>429 async fn test_nat_mapping_timeout_outbound_detects_timeout() -> Result<()> {
430 let nat = NetworkAddressTranslator::new(NatConfig {
431 nat_type: NatType {
432 mapping_behavior: EndpointDependencyType::EndpointIndependent,
433 filtering_behavior: EndpointDependencyType::EndpointIndependent,
434 hair_pining: false,
435 mapping_life_time: Duration::from_millis(100),
436 ..Default::default()
437 },
438 mapped_ips: vec![IpAddr::from_str(DEMO_IP)?],
439 ..Default::default()
440 })?;
441
442 let src = SocketAddr::from_str("192.168.0.2:1234")?;
443 let dst = SocketAddr::from_str("5.6.7.8:5678")?;
444
445 let oic = ChunkUdp::new(src, dst);
446
447 let oec = nat.translate_outbound(&oic).await?.unwrap();
448 assert_eq!(nat.outbound_map_len().await, 1, "should match");
449 assert_eq!(nat.inbound_map_len().await, 1, "should match");
450
451 log::debug!("o-original : {}", oic);
452 log::debug!("o-translated: {}", oec);
453
454 // sleep long enough for the mapping to expire
455 tokio::time::sleep(Duration::from_millis(125)).await;
456
457 let iec = ChunkUdp::new(
458 SocketAddr::new(dst.ip(), dst.port()),
459 SocketAddr::new(oec.source_addr().ip(), oec.source_addr().port()),
460 );
461
462 log::debug!("i-original : {}", iec);
463
464 let result = nat.translate_inbound(&iec).await;
465 assert!(result.is_err(), "should drop");
466 assert_eq!(nat.outbound_map_len().await, 0, "should match");
467 assert_eq!(nat.inbound_map_len().await, 0, "should match");
468
469 Ok(())
470 }
471
472 #[tokio::test]
test_nat1to1_bahavior_one_mapping() -> Result<()>473 async fn test_nat1to1_bahavior_one_mapping() -> Result<()> {
474 let nat = NetworkAddressTranslator::new(NatConfig {
475 nat_type: NatType {
476 mode: NatMode::Nat1To1,
477 ..Default::default()
478 },
479 mapped_ips: vec![IpAddr::from_str(DEMO_IP)?],
480 local_ips: vec![IpAddr::from_str("10.0.0.1")?],
481 ..Default::default()
482 })?;
483
484 let src = SocketAddr::from_str("10.0.0.1:1234")?;
485 let dst = SocketAddr::from_str("5.6.7.8:5678")?;
486
487 let oic = ChunkUdp::new(src, dst);
488
489 let oec = nat.translate_outbound(&oic).await?.unwrap();
490 assert_eq!(nat.outbound_map_len().await, 0, "should match");
491 assert_eq!(nat.inbound_map_len().await, 0, "should match");
492
493 log::debug!("o-original : {}", oic);
494 log::debug!("o-translated: {}", oec);
495
496 assert_eq!(
497 "1.2.3.4:1234",
498 oec.source_addr().to_string(),
499 "should match"
500 );
501
502 let iec = ChunkUdp::new(
503 SocketAddr::new(dst.ip(), dst.port()),
504 SocketAddr::new(oec.source_addr().ip(), oec.source_addr().port()),
505 );
506
507 log::debug!("i-original : {}", iec);
508
509 let iic = nat.translate_inbound(&iec).await?.unwrap();
510
511 log::debug!("i-translated: {}", iic);
512
513 assert_eq!(oic.source_addr(), iic.destination_addr(), "should match");
514
515 Ok(())
516 }
517
518 #[tokio::test]
test_nat1to1_bahavior_more_mapping() -> Result<()>519 async fn test_nat1to1_bahavior_more_mapping() -> Result<()> {
520 let nat = NetworkAddressTranslator::new(NatConfig {
521 nat_type: NatType {
522 mode: NatMode::Nat1To1,
523 ..Default::default()
524 },
525 mapped_ips: vec![IpAddr::from_str(DEMO_IP)?, IpAddr::from_str("1.2.3.5")?],
526 local_ips: vec![IpAddr::from_str("10.0.0.1")?, IpAddr::from_str("10.0.0.2")?],
527 ..Default::default()
528 })?;
529
530 // outbound translation
531
532 let before = ChunkUdp::new(
533 SocketAddr::from_str("10.0.0.1:1234")?,
534 SocketAddr::from_str("5.6.7.8:5678")?,
535 );
536
537 let after = nat.translate_outbound(&before).await?.unwrap();
538 assert_eq!(
539 after.source_addr().to_string(),
540 "1.2.3.4:1234",
541 "should match"
542 );
543
544 let before = ChunkUdp::new(
545 SocketAddr::from_str("10.0.0.2:1234")?,
546 SocketAddr::from_str("5.6.7.8:5678")?,
547 );
548
549 let after = nat.translate_outbound(&before).await?.unwrap();
550 assert_eq!(
551 after.source_addr().to_string(),
552 "1.2.3.5:1234",
553 "should match"
554 );
555
556 // inbound translation
557
558 let before = ChunkUdp::new(
559 SocketAddr::from_str("5.6.7.8:5678")?,
560 SocketAddr::from_str(&format!("{}:{}", DEMO_IP, 2525))?,
561 );
562
563 let after = nat.translate_inbound(&before).await?.unwrap();
564 assert_eq!(
565 after.destination_addr().to_string(),
566 "10.0.0.1:2525",
567 "should match"
568 );
569
570 let before = ChunkUdp::new(
571 SocketAddr::from_str("5.6.7.8:5678")?,
572 SocketAddr::from_str("1.2.3.5:9847")?,
573 );
574
575 let after = nat.translate_inbound(&before).await?.unwrap();
576 assert_eq!(
577 after.destination_addr().to_string(),
578 "10.0.0.2:9847",
579 "should match"
580 );
581
582 Ok(())
583 }
584
585 #[tokio::test]
test_nat1to1_bahavior_failure() -> Result<()>586 async fn test_nat1to1_bahavior_failure() -> Result<()> {
587 // 1:1 NAT requires more than one mapping
588 let result = NetworkAddressTranslator::new(NatConfig {
589 nat_type: NatType {
590 mode: NatMode::Nat1To1,
591 ..Default::default()
592 },
593 ..Default::default()
594 });
595 assert!(result.is_err(), "should fail");
596
597 // 1:1 NAT requires the same number of mappedIPs and localIPs
598 let result = NetworkAddressTranslator::new(NatConfig {
599 nat_type: NatType {
600 mode: NatMode::Nat1To1,
601 ..Default::default()
602 },
603 mapped_ips: vec![IpAddr::from_str(DEMO_IP)?, IpAddr::from_str("1.2.3.5")?],
604 local_ips: vec![IpAddr::from_str("10.0.0.1")?],
605 ..Default::default()
606 });
607 assert!(result.is_err(), "should fail");
608
609 // drop outbound or inbound chunk with no route in 1:1 NAT
610 let nat = NetworkAddressTranslator::new(NatConfig {
611 nat_type: NatType {
612 mode: NatMode::Nat1To1,
613 ..Default::default()
614 },
615 mapped_ips: vec![IpAddr::from_str(DEMO_IP)?],
616 local_ips: vec![IpAddr::from_str("10.0.0.1")?],
617 ..Default::default()
618 })?;
619
620 let before = ChunkUdp::new(
621 SocketAddr::from_str("10.0.0.2:1234")?, // no external mapping for this
622 SocketAddr::from_str("5.6.7.8:5678")?,
623 );
624
625 let after = nat.translate_outbound(&before).await?;
626 assert!(after.is_none(), "should be nil");
627
628 let before = ChunkUdp::new(
629 SocketAddr::from_str("5.6.7.8:5678")?,
630 SocketAddr::from_str("10.0.0.2:1234")?, // no local mapping for this
631 );
632
633 let result = nat.translate_inbound(&before).await;
634 assert!(result.is_err(), "should fail");
635
636 Ok(())
637 }
638