diff options
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 59 |
1 files changed, 58 insertions, 1 deletions
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) { |