Skip to content

Commit c657190

Browse files
committed
Add TcpOptions
1 parent 8f43ba9 commit c657190

4 files changed

Lines changed: 75 additions & 22 deletions

File tree

examples/tun.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
9292
});
9393

9494
let mut ipstack_config = ipstack::IpStackConfig::default();
95+
let mut tcp_config = ipstack::TcpConfig::default();
96+
tcp_config.options = Some(vec![ipstack::TcpOptions::MaximumSegmentSize(1460)]);
97+
ipstack_config.with_tcp_config(tcp_config);
9598
ipstack_config.mtu(MTU);
9699
let mut tcp_config = ipstack::TcpConfig::default();
97100
tcp_config.timeout = std::time::Duration::from_secs(args.tcp_timeout);

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ mod packet;
1919
mod stream;
2020

2121
pub use self::error::{IpStackError, Result};
22-
pub use self::stream::TcpConfig;
2322
pub use self::stream::{IpStackStream, IpStackTcpStream, IpStackUdpStream, IpStackUnknownTransport};
23+
pub use self::stream::{TcpConfig, TcpOptions};
2424
pub use etherparse::IpNumber;
2525

2626
#[cfg(unix)]

src/stream/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
22

33
pub use self::tcp::IpStackTcpStream;
4-
pub use self::tcp::TcpConfig;
4+
pub use self::tcp::{TcpConfig, TcpOptions};
55
pub use self::udp::IpStackUdpStream;
66
pub use self::unknown::IpStackUnknownTransport;
77

src/stream/tcp.rs

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::{
99
},
1010
stream::tcb::{PacketType, Tcb, TcpState},
1111
};
12-
use etherparse::{IpNumber, Ipv4Header, Ipv6FlowLabel, TcpHeader};
12+
use etherparse::{IpNumber, Ipv4Header, Ipv6FlowLabel, TcpHeader, TcpOptionElement};
1313
use std::{
1414
future::Future,
1515
io::ErrorKind::{BrokenPipe, ConnectionRefused, InvalidInput, UnexpectedEof},
@@ -43,6 +43,15 @@ pub struct TcpConfig {
4343
pub timeout: Duration,
4444
/// Timeout for the TIME_WAIT state. Default is 2 seconds.
4545
pub two_msl: Duration,
46+
/// TCP options
47+
pub options: Option<Vec<TcpOptions>>,
48+
}
49+
50+
#[non_exhaustive]
51+
#[derive(Debug, Clone)]
52+
pub enum TcpOptions {
53+
/// Maximum segment size (MSS) for TCP connections. Default is 1460 bytes.
54+
MaximumSegmentSize(u16),
4655
}
4756

4857
impl Default for TcpConfig {
@@ -53,6 +62,7 @@ impl Default for TcpConfig {
5362
close_wait_timeout: CLOSE_WAIT_TIMEOUT,
5463
timeout: TIMEOUT,
5564
two_msl: TWO_MSL,
65+
options: Default::default(),
5666
}
5767
}
5868
}
@@ -134,7 +144,7 @@ impl IpStackTcpStream {
134144
let tuple = NetworkTuple::new(src_addr, dst_addr, true);
135145
if !tcp.syn {
136146
if !tcp.rst
137-
&& let Err(err) = write_packet_to_device(&up_packet_sender, tuple, &tcb, ACK | RST, None, None)
147+
&& let Err(err) = write_packet_to_device(&up_packet_sender, tuple, &tcb, None, ACK | RST, None, None)
138148
{
139149
log::warn!("Error sending RST/ACK packet: {err}");
140150
}
@@ -222,7 +232,7 @@ impl AsyncRead for IpStackTcpStream {
222232
let l_info = format!("local {{ seq: {seq}, ack: {ack} }}");
223233
log::warn!("{network_tuple} {state:?}: [poll_read] {l_info}, session timeout reached, closing forcefully...");
224234
let sender = &self.up_packet_sender;
225-
write_packet_to_device(sender, network_tuple, &tcb, ACK | RST, None, None)?;
235+
write_packet_to_device(sender, network_tuple, &tcb, None, ACK | RST, None, None)?;
226236
tcb.change_state(TcpState::Closed);
227237
let state = tcb.get_state();
228238
log::warn!("{network_tuple} {state:?}: [poll_read] {l_info}, session notified to close");
@@ -281,7 +291,7 @@ impl AsyncWrite for IpStackTcpStream {
281291

282292
let mut tcb = self.tcb.lock().unwrap();
283293
let sender = &self.up_packet_sender;
284-
let payload_len = write_packet_to_device(sender, nt, &tcb, ACK | PSH, None, Some(buf.to_vec()))?;
294+
let payload_len = write_packet_to_device(sender, nt, &tcb, None, ACK | PSH, None, Some(buf.to_vec()))?;
285295
tcb.add_inflight_packet(buf[..payload_len].to_vec())?;
286296

287297
let (state, seq, ack) = (tcb.get_state(), tcb.get_seq(), tcb.get_ack());
@@ -335,7 +345,7 @@ fn send_fin_n_change_state_to_fin_wait1(hint: &str, nt: NetworkTuple, sender: &P
335345
}
336346

337347
log::debug!("{nt} {state:?}: {hint} actively send a farewell packet to the other side...");
338-
write_packet_to_device(sender, nt, tcb, ACK | FIN, None, None)?;
348+
write_packet_to_device(sender, nt, tcb, None, ACK | FIN, None, None)?;
339349
tcb.increase_seq();
340350
tcb.change_state(TcpState::FinWait1);
341351
let state = tcb.get_state();
@@ -437,7 +447,15 @@ async fn tcp_main_logic_loop(
437447
let (seq, ack) = (tcb.get_seq().0, tcb.get_ack().0);
438448
let l_info = format!("local {{ seq: {seq}, ack: {ack} }}");
439449
log::trace!("{network_tuple} {state:?}: {l_info} session begins");
440-
write_packet_to_device(&up_packet_sender, network_tuple, &tcb, ACK | SYN, None, None)?;
450+
write_packet_to_device(
451+
&up_packet_sender,
452+
network_tuple,
453+
&tcb,
454+
config.options.as_ref(),
455+
ACK | SYN,
456+
None,
457+
None,
458+
)?;
441459
tcb.increase_seq();
442460
tcb.change_state(TcpState::SynReceived);
443461
let state = tcb.get_state();
@@ -483,7 +501,7 @@ async fn tcp_main_logic_loop(
483501
return;
484502
}
485503
log::debug!("{nt} {state:?}: {hint} timer expired, resending ACK|FIN (retry {idx}/{last_ack_max_retries})");
486-
_ = write_packet_to_device(&pkt_sdr, nt, &tcb, ACK | FIN, None, None);
504+
_ = write_packet_to_device(&pkt_sdr, nt, &tcb, None, ACK | FIN, None, None);
487505
}
488506
}
489507
{
@@ -512,7 +530,7 @@ async fn tcp_main_logic_loop(
512530
return Ok(());
513531
}
514532
log::warn!("{nt} {state:?}: Upstream timeout, forcing FIN");
515-
write_packet_to_device(&up_packet_sender, nt, &tcb, ACK | FIN, None, None)?;
533+
write_packet_to_device(&up_packet_sender, nt, &tcb, None, ACK | FIN, None, None)?;
516534
tcb.increase_seq();
517535
tcb.change_state(TcpState::LastAck);
518536
let new_state = tcb.get_state();
@@ -581,7 +599,15 @@ async fn tcp_main_logic_loop(
581599
for packet in tcb.collect_timed_out_inflight_packets() {
582600
let (seq, count) = (packet.seq, packet.retransmit_count);
583601
log::debug!("{network_tuple} inflight packet retransmission timeout: {seq:?}, retransmit_count: {count}",);
584-
write_packet_to_device(&up_packet_sender, network_tuple, &tcb, ACK | PSH, Some(seq), Some(packet.payload))?;
602+
write_packet_to_device(
603+
&up_packet_sender,
604+
network_tuple,
605+
&tcb,
606+
None,
607+
ACK | PSH,
608+
Some(seq),
609+
Some(packet.payload),
610+
)?;
585611
}
586612

587613
let pkt_type = tcb.check_pkt_type(tcp_header, &payload);
@@ -611,7 +637,7 @@ async fn tcp_main_logic_loop(
611637
write_notify.lock().unwrap().take().map(|w| w.wake_by_ref()).unwrap_or(());
612638
}
613639
PacketType::KeepAlive => {
614-
write_packet_to_device(&up_packet_sender, network_tuple, &tcb, ACK, None, None)?;
640+
write_packet_to_device(&up_packet_sender, network_tuple, &tcb, None, ACK, None, None)?;
615641
}
616642
PacketType::RetransmissionRequest => {
617643
if let Some(packet) = tcb.find_inflight_packet(incoming_ack) {
@@ -620,7 +646,7 @@ async fn tcp_main_logic_loop(
620646
"{network_tuple} {state:?}: {l_info}, {pkt_type:?}, retransmission request, seq = {s}, len = {}",
621647
p.len()
622648
);
623-
write_packet_to_device(&up_packet_sender, network_tuple, &tcb, ACK | PSH, Some(s), Some(p))?;
649+
write_packet_to_device(&up_packet_sender, network_tuple, &tcb, None, ACK | PSH, Some(s), Some(p))?;
624650
}
625651
}
626652
PacketType::NewPacket => {
@@ -637,7 +663,7 @@ async fn tcp_main_logic_loop(
637663
} else if flags == (ACK | FIN) {
638664
// The other side is closing the connection, we need to send an ACK and change state to CloseWait
639665
tcb.increase_ack();
640-
write_packet_to_device(&up_packet_sender, network_tuple, &tcb, ACK, None, None)?;
666+
write_packet_to_device(&up_packet_sender, network_tuple, &tcb, None, ACK, None, None)?;
641667
tcb.change_state(TcpState::CloseWait);
642668

643669
let s = tcb.get_state();
@@ -647,7 +673,7 @@ async fn tcp_main_logic_loop(
647673
log::trace!("{network_tuple} {s:?}: {l_info}, {pkt_type:?}, closed by the other side, no upstream data");
648674

649675
// Here we don't wait, just send FIN to the other side and change state to LastAck directly,
650-
write_packet_to_device(&up_packet_sender, network_tuple, &tcb, ACK | FIN, None, None)?;
676+
write_packet_to_device(&up_packet_sender, network_tuple, &tcb, None, ACK | FIN, None, None)?;
651677
tcb.increase_seq();
652678
tcb.change_state(TcpState::LastAck);
653679

@@ -696,7 +722,7 @@ async fn tcp_main_logic_loop(
696722
}
697723
TcpState::CloseWait => {
698724
if flags & ACK == ACK && tcb.get_inflight_packets_total_len() == 0 {
699-
write_packet_to_device(&up_packet_sender, network_tuple, &tcb, ACK | FIN, None, None)?;
725+
write_packet_to_device(&up_packet_sender, network_tuple, &tcb, None, ACK | FIN, None, None)?;
700726
tcb.increase_seq();
701727
tcb.change_state(TcpState::LastAck);
702728
let new_state = tcb.get_state();
@@ -734,7 +760,7 @@ async fn tcp_main_logic_loop(
734760
if flags & (ACK | FIN) == (ACK | FIN) && len == 0 {
735761
// If the received packet is an ACK with FIN, we need to send an ACK and change state to TimeWait directly, not to FinWait2
736762
tcb.increase_ack();
737-
write_packet_to_device(&up_packet_sender, network_tuple, &tcb, ACK, None, None)?;
763+
write_packet_to_device(&up_packet_sender, network_tuple, &tcb, None, ACK, None, None)?;
738764
tcb.change_state(TcpState::TimeWait);
739765

740766
tokio::spawn(task_wait_to_close(tcb_clone.clone(), exit_notifier, network_tuple, config.two_msl));
@@ -758,7 +784,7 @@ async fn tcp_main_logic_loop(
758784
TcpState::FinWait2 => {
759785
if flags & (ACK | FIN) == (ACK | FIN) && len == 0 {
760786
tcb.increase_ack();
761-
write_packet_to_device(&up_packet_sender, network_tuple, &tcb, ACK, None, None)?;
787+
write_packet_to_device(&up_packet_sender, network_tuple, &tcb, None, ACK, None, None)?;
762788
tcb.change_state(TcpState::TimeWait);
763789
tokio::spawn(task_wait_to_close(tcb_clone.clone(), exit_notifier, network_tuple, config.two_msl));
764790
let new_state = tcb.get_state();
@@ -771,7 +797,7 @@ async fn tcp_main_logic_loop(
771797
}
772798
} else if flags & ACK == ACK && len > 0 {
773799
if pkt_type == PacketType::KeepAlive {
774-
write_packet_to_device(&up_packet_sender, network_tuple, &tcb, ACK, None, None)?;
800+
write_packet_to_device(&up_packet_sender, network_tuple, &tcb, None, ACK, None, None)?;
775801
} else {
776802
// if the other side is still sending data, we need to deal with it like PacketStatus::NewPacket
777803
tcb.add_unordered_packet(incoming_seq, payload);
@@ -791,7 +817,7 @@ async fn tcp_main_logic_loop(
791817
}
792818
TcpState::TimeWait => {
793819
if flags & (ACK | FIN) == (ACK | FIN) {
794-
write_packet_to_device(&up_packet_sender, network_tuple, &tcb, ACK, None, None)?;
820+
write_packet_to_device(&up_packet_sender, network_tuple, &tcb, None, ACK, None, None)?;
795821
// wait to timeout, can't call `tcb.change_state(TcpState::Closed);` to change state here
796822
// now we need to wait for the timeout to reach...
797823
}
@@ -824,7 +850,7 @@ fn extract_data_n_write_upstream(
824850
log::trace!("{network_tuple} {state:?}: {l_info} {hint} receiving data, len = {}", data.len());
825851
data_tx.send(data).map_err(|e| std::io::Error::new(BrokenPipe, e))?;
826852
read_notify.lock().unwrap().take().map(|w| w.wake_by_ref()).unwrap_or(());
827-
write_packet_to_device(up_packet_sender, network_tuple, tcb, ACK, None, None)?;
853+
write_packet_to_device(up_packet_sender, network_tuple, tcb, None, ACK, None, None)?;
828854
}
829855
Ok(())
830856
}
@@ -835,6 +861,7 @@ pub(crate) fn write_packet_to_device(
835861
up_packet_sender: &PacketSender,
836862
tuple: NetworkTuple,
837863
tcb: &Tcb,
864+
options: Option<&Vec<TcpOptions>>,
838865
flags: u8,
839866
seq: Option<SeqNum>,
840867
payload: Option<Vec<u8>>,
@@ -844,7 +871,18 @@ pub(crate) fn write_packet_to_device(
844871
let (ack, window_size) = (tcb.get_ack().0, tcb.get_recv_window().max(tcb.get_mtu()));
845872
let (src, dst) = (tuple.dst, tuple.src); // Note: The address is reversed here
846873
let calc = |ip_header_len: usize, tcp_header_len: usize| tcb.calculate_payload_max_len(ip_header_len, tcp_header_len);
847-
let packet = create_raw_packet(src, dst, calc, flags, TTL, seq, ack, window_size, payload.unwrap_or_default())?;
874+
let packet = create_raw_packet(
875+
src,
876+
dst,
877+
calc,
878+
flags,
879+
TTL,
880+
seq,
881+
ack,
882+
window_size,
883+
payload.unwrap_or_default(),
884+
options,
885+
)?;
848886
let len = packet.payload.as_ref().map(|p| p.len()).unwrap_or(0);
849887
up_packet_sender.send(packet).map_err(|e| Error::new(UnexpectedEof, e))?;
850888
Ok(len)
@@ -861,6 +899,7 @@ pub(crate) fn create_raw_packet(
861899
ack: u32,
862900
win: u16,
863901
mut payload: Vec<u8>,
902+
options: Option<&Vec<TcpOptions>>,
864903
) -> std::io::Result<NetworkPacket> {
865904
let mut tcp_header = etherparse::TcpHeader::new(src_addr.port(), dst_addr.port(), seq, win);
866905
tcp_header.acknowledgment_number = ack;
@@ -870,6 +909,17 @@ pub(crate) fn create_raw_packet(
870909
tcp_header.fin = flags & FIN != 0;
871910
tcp_header.psh = flags & PSH != 0;
872911

912+
if let Some(opts) = options {
913+
let mut tcp_options = Vec::new();
914+
for opt in opts {
915+
match opt {
916+
TcpOptions::MaximumSegmentSize(mss) => tcp_options.push(TcpOptionElement::MaximumSegmentSize(*mss)),
917+
}
918+
}
919+
tcp_header
920+
.set_options(&tcp_options)
921+
.map_err(|e| std::io::Error::new(InvalidInput, e))?;
922+
}
873923
let ip_header = match (src_addr.ip(), dst_addr.ip()) {
874924
(std::net::IpAddr::V4(src), std::net::IpAddr::V4(dst)) => {
875925
let mut ip_h =

0 commit comments

Comments
 (0)