fix(fake-tcp): when connect()-ing, attempt to get ephemeral port using algorithm similar to Linux (#162)

* fix(fake-tcp): when `connect()`-ing, attempt to get ephemeral port 5 times to reduce the chance
of panicking

Fixes #79
This commit is contained in:
Datong Sun 2024-11-20 22:57:11 +08:00 committed by GitHub
parent 60f24d2563
commit e86c5c5c50
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -50,8 +50,10 @@ use rand::prelude::*;
use std::collections::{HashMap, HashSet};
use std::fmt;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::{Arc, RwLock};
use std::sync::{
atomic::{AtomicU32, Ordering},
Arc, RwLock,
};
use tokio::sync::broadcast;
use tokio::sync::mpsc;
use tokio::time;
@ -401,7 +403,7 @@ impl Stack {
/// the connection attempt failed.
pub async fn connect(&mut self, addr: SocketAddr) -> Option<Socket> {
let mut rng = SmallRng::from_entropy();
let local_port: u16 = rng.gen_range(1024..65535);
for local_port in rng.gen_range(32768..=60999)..=60999 {
let local_addr = SocketAddr::new(
if addr.is_ipv4() {
IpAddr::V4(self.local_ip)
@ -411,7 +413,20 @@ impl Stack {
local_port,
);
let tuple = AddrTuple::new(local_addr, addr);
let (mut sock, incoming) = Socket::new(
let mut sock;
{
let mut tuples = self.shared.tuples.write().unwrap();
if tuples.contains_key(&tuple) {
trace!(
"Fake TCP connection to {}, local port number {} already in use, trying another one",
addr, local_port
);
continue;
}
let incoming;
(sock, incoming) = Socket::new(
self.shared.clone(),
self.shared.tun.choose(&mut rng).unwrap().clone(),
local_addr,
@ -420,12 +435,17 @@ impl Stack {
State::Idle,
);
{
let mut tuples = self.shared.tuples.write().unwrap();
assert!(tuples.insert(tuple, incoming.clone()).is_none());
assert!(tuples.insert(tuple, incoming).is_none());
}
sock.connect().await.map(|_| sock)
return sock.connect().await.map(|_| sock);
}
error!(
"Fake TCP connection to {} failed, emphemeral port number exhausted",
addr
);
None
}
async fn reader_task(