Skip to content

Commit 8e1f16f

Browse files
committed
ts_tunnel: drop keepalive packets after decryption
Fixes #287 Signed-off-by: David Anderson <danderson@tailscale.com> Change-Id: I5ea455a9d639124dcdcacb063ce672ae6a6a6964
1 parent 6203967 commit 8e1f16f

2 files changed

Lines changed: 29 additions & 27 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Put changes for the upcoming release here!
1212
configure them to be).
1313
[#292](https://github.com/tailscale/tailscale-rs/pull/292).
1414
- Fixed(ts_tunnel): adjust session rotation logic to match the spec (#286)
15+
- Fixed(ts_tunnel): don't yield empty decrypted keepalive packets to the caller (#287)
1516

1617
## [0.4.0](https://github.com/tailscale/tailscale-rs/releases/tag/v0.4.0) - 2026-07-08
1718

ts_tunnel/src/endpoint.rs

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use core::time::Duration;
2-
use std::{collections::HashMap, time::Instant};
2+
use std::{collections::HashMap, iter::once, time::Instant};
33

44
use itertools::Itertools;
55
use ts_keys::{NodeKeyPair, NodePublicKey};
@@ -68,9 +68,9 @@ impl Peer {
6868
now: Instant,
6969
out: &mut SendResult,
7070
) {
71-
if let Some(mut packets) = self.session.send(packets, &mut endpoint.ids, now) {
71+
if let Some(packets) = self.session.send(packets, &mut endpoint.ids, now) {
7272
tracing::trace!("enqueueing packets to peer");
73-
out.queue_to_peer(self.id).append(&mut packets);
73+
out.queue_to_peer(self.id, packets);
7474
// Fall through to check if the session is in need of rotation.
7575
}
7676

@@ -156,8 +156,8 @@ impl Peer {
156156
return;
157157
};
158158

159-
let (expiry, mut packets) = self.session.activate(session, &mut endpoint.ids, now, true);
160-
out.queue_to_peer(self.id).append(&mut packets);
159+
let (expiry, packets) = self.session.activate(session, &mut endpoint.ids, now, true);
160+
out.queue_to_peer(self.id, packets);
161161
if let Some(handle) = self.session_cleanup.take() {
162162
handle.cancel();
163163
};
@@ -177,9 +177,9 @@ impl Peer {
177177
out: &mut RecvResult,
178178
) {
179179
if let Some(recv) = self.session.get_recv(session_id, &mut endpoint.ids, now) {
180-
let mut packets = recv.decrypt(packets);
180+
let packets = recv.decrypt(packets);
181181
if !packets.is_empty() {
182-
out.queue_to_local(self.id).append(&mut packets);
182+
out.queue_to_local(self.id, packets);
183183
self.schedule_keepalive(&mut endpoint.scheduler, now);
184184
if self.session.needs_rotation(now) {
185185
self.start_handshake(endpoint, now, out);
@@ -188,19 +188,19 @@ impl Peer {
188188
return;
189189
}
190190

191-
let Some((session, mut packets)) = self.handshake.confirm(session_id, packets) else {
191+
let Some((session, packets)) = self.handshake.confirm(session_id, packets) else {
192192
// TODO: log
193193
return;
194194
};
195195

196-
out.queue_to_local(self.id).append(&mut packets);
196+
out.queue_to_local(self.id, packets);
197197
self.schedule_keepalive(&mut endpoint.scheduler, now);
198198

199-
let (expiry, mut packets_for_peer) =
199+
let (expiry, packets_for_peer) =
200200
self.session
201201
.activate(session, &mut endpoint.ids, now, false);
202202
if !packets_for_peer.is_empty() {
203-
out.queue_to_peer(self.id).append(&mut packets_for_peer);
203+
out.queue_to_peer(self.id, packets_for_peer);
204204
}
205205
if let Some(handle) = self.session_cleanup.take() {
206206
handle.cancel();
@@ -241,7 +241,7 @@ impl Peer {
241241
&self.cookie_sender,
242242
now,
243243
);
244-
out.queue_to_peer(self.id).push(packet);
244+
out.queue_to_peer(self.id, once(packet));
245245
}
246246

247247
fn handshake_timeout(
@@ -271,7 +271,7 @@ impl Peer {
271271
tracing::trace!("send keepalive: session expired, skipping");
272272
return;
273273
};
274-
out.queue_to_peer(self.id).push(packet);
274+
out.queue_to_peer(self.id, once(packet));
275275

276276
self.keepalive = None;
277277

@@ -320,7 +320,7 @@ impl Peer {
320320

321321
tracing::debug!(peer_id = ?self.id, ?session_id, "enqueue handshake start");
322322

323-
out.queue_to_peer(self.id).push(packet);
323+
out.queue_to_peer(self.id, once(packet));
324324
let tr = TimeRange::new_around(now + HANDSHAKE_TIMEOUT, Duration::from_millis(500));
325325

326326
let timeout = endpoint.scheduler.add(tr, Event::HandshakeTimeout(self.id));
@@ -554,7 +554,7 @@ impl Endpoint {
554554
}
555555

556556
trait QueueToPeer {
557-
fn queue_to_peer(&mut self, peer: PeerId) -> &mut Vec<PacketMut>;
557+
fn queue_to_peer(&mut self, peer: PeerId, packets: impl IntoIterator<Item = PacketMut>);
558558
}
559559

560560
/// The outcome of attempting to send packets to peers.
@@ -565,8 +565,8 @@ pub struct SendResult {
565565
}
566566

567567
impl QueueToPeer for SendResult {
568-
fn queue_to_peer(&mut self, peer: PeerId) -> &mut Vec<PacketMut> {
569-
self.to_peers.entry(peer).or_default()
568+
fn queue_to_peer(&mut self, peer: PeerId, packets: impl IntoIterator<Item = PacketMut>) {
569+
self.to_peers.entry(peer).or_default().extend(packets);
570570
}
571571
}
572572

@@ -580,14 +580,17 @@ pub struct RecvResult {
580580
}
581581

582582
impl RecvResult {
583-
fn queue_to_local(&mut self, peer: PeerId) -> &mut Vec<PacketMut> {
584-
self.to_local.entry(peer).or_default()
583+
fn queue_to_local(&mut self, peer: PeerId, packets: impl IntoIterator<Item = PacketMut>) {
584+
self.to_local
585+
.entry(peer)
586+
.or_default()
587+
.extend(packets.into_iter().filter(|p| !p.is_empty()));
585588
}
586589
}
587590

588591
impl QueueToPeer for RecvResult {
589-
fn queue_to_peer(&mut self, peer: PeerId) -> &mut Vec<PacketMut> {
590-
self.to_peers.entry(peer).or_default()
592+
fn queue_to_peer(&mut self, peer: PeerId, packets: impl IntoIterator<Item = PacketMut>) {
593+
self.to_peers.entry(peer).or_default().extend(packets);
591594
}
592595
}
593596

@@ -599,8 +602,8 @@ pub struct EventResult {
599602
}
600603

601604
impl QueueToPeer for EventResult {
602-
fn queue_to_peer(&mut self, peer: PeerId) -> &mut Vec<PacketMut> {
603-
self.to_peers.entry(peer).or_default()
605+
fn queue_to_peer(&mut self, peer: PeerId, packets: impl IntoIterator<Item = PacketMut>) {
606+
self.to_peers.entry(peer).or_default().extend(packets);
604607
}
605608
}
606609

@@ -962,8 +965,7 @@ mod tests {
962965
p.assert_a_to_b([TransportData]);
963966
// B receives confirmation, finalizes rotation.
964967
p.recv_at_b(t.at(128));
965-
// TODO: assert that no packets are delivered. See https://github.com/tailscale/tailscale-rs/issues/287
966-
p.assert_received_at_b([PacketMut::new(0)]);
968+
assert_no_packets(&p.received_at_b);
967969
}
968970

969971
#[test]
@@ -1000,7 +1002,6 @@ mod tests {
10001002
p.assert_a_to_b([TransportData]);
10011003
// B receives confirmation, finalizes rotation.
10021004
p.recv_at_b(t.at(129));
1003-
// TODO: assert that no packets are delivered. See https://github.com/tailscale/tailscale-rs/issues/287
1004-
p.assert_received_at_b([PacketMut::new(0)]);
1005+
assert_no_packets(&p.received_at_b);
10051006
}
10061007
}

0 commit comments

Comments
 (0)