diff options
author | HimbeerserverDE <himbeerserverde@gmail.com> | 2023-05-02 19:26:49 +0200 |
---|---|---|
committer | HimbeerserverDE <himbeerserverde@gmail.com> | 2023-05-02 19:31:51 +0200 |
commit | dc8b17410cec050ea62f65056b455644e5253126 (patch) | |
tree | 44ffe5b9cbff9ab9fc5a0da74e57c2c4816aa969 | |
parent | 37d27c66bb9a6300eee6b9a69a06325434c1fe22 (diff) |
implement (bidirectional) mss clamping0.1.2
-rw-r--r-- | Cargo.lock | 18 | ||||
-rw-r--r-- | Cargo.toml | 3 | ||||
-rw-r--r-- | src/error.rs | 6 | ||||
-rw-r--r-- | src/main.rs | 59 |
4 files changed, 83 insertions, 3 deletions
@@ -27,6 +27,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" [[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -238,6 +244,15 @@ dependencies = [ ] [[package]] +name = "etherparse" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "827292ea592108849932ad8e30218f8b1f21c0dfd0696698a18b5d0aed62d990" +dependencies = [ + "arrayvec", +] + +[[package]] name = "filetime" version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -925,9 +940,10 @@ dependencies = [ [[package]] name = "rsdsl_pppoe" -version = "0.1.1" +version = "0.1.2" dependencies = [ "byteorder", + "etherparse", "md5", "pppoe", "rand", @@ -1,6 +1,6 @@ [package] name = "rsdsl_pppoe" -version = "0.1.1" +version = "0.1.2" authors = ["HimbeerserverDE <himbeerserverde@gmail.com>"] license = "MIT" edition = "2021" @@ -9,6 +9,7 @@ edition = "2021" [dependencies] byteorder = "1.4.3" +etherparse = "0.13.0" md5 = "0.7.0" pppoe = { git = "https://github.com/rsdsl/pppoe-rs.git", version = "0.1.0", features = ["socket"] } rand = "0.8.5" diff --git a/src/error.rs b/src/error.rs index 1411f3a..d35730b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -65,6 +65,12 @@ pub enum Error { Pppoe(pppoe::error::Error), #[error("pppoe parse error: {0:?}")] PppoeParse(pppoe::error::ParseError), + #[error("etherparse read error: {0}")] + EtherParseRead(#[from] etherparse::ReadError), + #[error("etherparse tcp option write error: {0}")] + EtherParseTcpOptionWrite(#[from] etherparse::TcpOptionWriteError), + #[error("etherparse value error: {0}")] + EtherParseValue(#[from] etherparse::ValueError), #[error("rsdsl_netlinkd error")] RsdslNetlinkd(#[from] rsdsl_netlinkd::error::Error), #[error("serde_json error")] diff --git a/src/main.rs b/src/main.rs index 5a7f047..1be7d5f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,11 +8,14 @@ use std::sync::{Arc, Mutex}; use std::thread; use byteorder::{ByteOrder, NetworkEndian as NE}; +use etherparse::{Ipv4Header, TcpHeader, TcpOptionElement}; use pppoe::packet::IPV4; use rsdsl_ip_config::IpConfig; use rsdsl_netlinkd::link; use tun_tap::{Iface, Mode}; +const IPPROTO_TCP: u8 = 0x06; + fn prepend<T>(v: Vec<T>, s: &[T]) -> Vec<T> where T: Clone, @@ -22,6 +25,50 @@ where tmp } +fn clamp_mss_if_needed(buf: &mut [u8]) -> Result<()> { + let ipv4_header = Ipv4Header::from_slice(&buf[4..])?.0; + + if ipv4_header.protocol == IPPROTO_TCP { + let ipv4_header_bytes = ipv4_header.ihl() as usize * 4; + + let mut tcp_header = TcpHeader::from_slice(&buf[4 + ipv4_header_bytes..])?.0; + + if tcp_header.syn { + let tcp_header_bytes = tcp_header.header_len() as usize; + + let mut opts = Vec::new(); + for opt in tcp_header.options_iterator() { + match opt { + Ok(mut opt) => { + if let TcpOptionElement::MaximumSegmentSize(_) = opt { + opt = TcpOptionElement::MaximumSegmentSize(1492); + } + + opts.push(opt); + } + Err(e) => println!("[pppoe] ignore invalid tcp opt: {}", e), + } + } + + tcp_header.set_options(&opts)?; + tcp_header.checksum = tcp_header.calc_checksum_ipv4( + &ipv4_header, + &buf[4 + ipv4_header_bytes + tcp_header_bytes..], + )?; + + let tcp_header_bytes = tcp_header.header_len() as usize; + + let mut hdr = Vec::new(); + tcp_header.write(&mut hdr)?; + + buf[4 + ipv4_header_bytes..4 + ipv4_header_bytes + tcp_header_bytes] + .copy_from_slice(&hdr); + } + } + + Ok(()) +} + fn tun2ppp(tx: mpsc::Sender<Option<Vec<u8>>>, tun: Arc<Iface>) -> Result<()> { loop { let mut buf = [0; 4 + 1492]; @@ -32,7 +79,7 @@ fn tun2ppp(tx: mpsc::Sender<Option<Vec<u8>>>, tun: Arc<Iface>) -> Result<()> { continue; } }; - let buf = &buf[..n]; + let buf = &mut buf[..n]; let ether_type = NE::read_u16(&buf[2..4]); if ether_type != IPV4 { @@ -43,6 +90,11 @@ fn tun2ppp(tx: mpsc::Sender<Option<Vec<u8>>>, tun: Arc<Iface>) -> Result<()> { continue; } + match clamp_mss_if_needed(buf) { + Ok(_) => {} + Err(e) => println!("[pppoe] ignore outbound mss clamping error: {}", e), + } + tx.send(Some(buf[4..].to_vec()))?; } } @@ -54,6 +106,11 @@ fn ppp2tun(rx: Arc<Mutex<mpsc::Receiver<Vec<u8>>>>, tun: Arc<Iface>) -> Result<( NE::write_u16(&mut packet_info[2..4], IPV4); while let Ok(mut buf) = rx.recv() { + match clamp_mss_if_needed(&mut buf) { + Ok(_) => {} + Err(e) => println!("[pppoe] ignore inbound mss clamping error: {}", e), + } + buf = prepend(buf, &packet_info); let n = match tun.send(&buf) { |