Skip to content

Commit a54589c

Browse files
authored
Merge pull request #1063 from cvengler/syn-ack
Allow withholding the SYN|ACK packet by user code
2 parents e000f15 + 029fd26 commit a54589c

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ defmt = ["dep:defmt", "heapless/defmt-03"]
7272
"socket-raw" = ["socket"]
7373
"socket-udp" = ["socket"]
7474
"socket-tcp" = ["socket"]
75+
"socket-tcp-pause-synack" = ["socket-tcp"]
7576
"socket-icmp" = ["socket"]
7677
"socket-dhcpv4" = ["socket", "medium-ethernet", "proto-dhcpv4"]
7778
"socket-dns" = ["socket", "proto-dns"]

src/socket/tcp.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,10 @@ pub struct Socket<'a> {
543543
rx_waker: WakerRegistration,
544544
#[cfg(feature = "async")]
545545
tx_waker: WakerRegistration,
546+
547+
/// If this is set, we will not send a SYN|ACK until this is unset.
548+
#[cfg(feature = "socket-tcp-pause-synack")]
549+
synack_paused: bool,
546550
}
547551

548552
const DEFAULT_MSS: usize = 536;
@@ -606,6 +610,9 @@ impl<'a> Socket<'a> {
606610
rx_waker: WakerRegistration::new(),
607611
#[cfg(feature = "async")]
608612
tx_waker: WakerRegistration::new(),
613+
614+
#[cfg(feature = "socket-tcp-pause-synack")]
615+
synack_paused: false,
609616
}
610617
}
611618

@@ -724,6 +731,16 @@ impl<'a> Socket<'a> {
724731
self.nagle
725732
}
726733

734+
/// Pause sending of SYN|ACK packets.
735+
///
736+
/// When this flag is set, the socket will get stuck in `SynReceived` state without sending
737+
/// any SYN|ACK packets back, until this flag is unset. This is useful for certain niche TCP
738+
/// proxy usecases.
739+
#[cfg(feature = "socket-tcp-pause-synack")]
740+
pub fn pause_synack(&mut self, pause: bool) {
741+
self.synack_paused = pause;
742+
}
743+
727744
/// Return the current window field value, including scaling according to RFC 1323.
728745
///
729746
/// Used in internal calculations as well as packet generation.
@@ -2372,6 +2389,11 @@ impl<'a> Socket<'a> {
23722389
.on_retransmit(cx.now());
23732390
}
23742391

2392+
#[cfg(feature = "socket-tcp-pause-synack")]
2393+
if matches!(self.state, State::SynReceived) && self.synack_paused {
2394+
return Ok(());
2395+
}
2396+
23752397
// Decide whether we're sending a packet.
23762398
if self.seq_to_transmit(cx) {
23772399
// If we have data to transmit and it fits into partner's window, do it.
@@ -3332,6 +3354,37 @@ mod test {
33323354
sanity!(s, socket_established());
33333355
}
33343356

3357+
#[cfg(feature = "socket-tcp-pause-synack")]
3358+
#[test]
3359+
fn test_syn_paused_ack() {
3360+
let mut s = socket_syn_received();
3361+
3362+
s.pause_synack(true);
3363+
recv_nothing!(s);
3364+
assert_eq!(s.state, State::SynReceived);
3365+
3366+
s.pause_synack(false);
3367+
recv!(
3368+
s,
3369+
[TcpRepr {
3370+
control: TcpControl::Syn,
3371+
seq_number: LOCAL_SEQ,
3372+
ack_number: Some(REMOTE_SEQ + 1),
3373+
max_seg_size: Some(BASE_MSS),
3374+
..RECV_TEMPL
3375+
}]
3376+
);
3377+
send!(
3378+
s,
3379+
TcpRepr {
3380+
seq_number: REMOTE_SEQ + 1,
3381+
ack_number: Some(LOCAL_SEQ + 1),
3382+
..SEND_TEMPL
3383+
}
3384+
);
3385+
assert_eq!(s.state, State::Established);
3386+
}
3387+
33353388
#[test]
33363389
fn test_syn_received_ack_too_low() {
33373390
let mut s = socket_syn_received();

0 commit comments

Comments
 (0)