diff options
author | HimbeerserverDE <himbeerserverde@gmail.com> | 2023-05-06 22:51:51 +0200 |
---|---|---|
committer | HimbeerserverDE <himbeerserverde@gmail.com> | 2023-05-06 22:51:51 +0200 |
commit | 8ce51538369265a1d3f10edea233d2c1437ec6c1 (patch) | |
tree | 319fc1e30b4ce7085fa63269f6c454d97fe68967 /src/main.rs | |
parent | a06f66a8eaa8bd5df0954968bd585366b842b692 (diff) |
recv 6in4 traffic and write to tun
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 122 |
1 files changed, 121 insertions, 1 deletions
diff --git a/src/main.rs b/src/main.rs index 9abd562..ba14b17 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,19 @@ use std::fs::File; +use std::io::{Read, Write}; use std::net::{Ipv4Addr, Ipv6Addr}; use std::path::Path; +use std::sync::Arc; use std::thread; use std::time::Duration; +use byteorder::{ByteOrder, NetworkEndian as NE}; use ipnet::Ipv6Net; use notify::event::{CreateKind, ModifyKind}; use notify::{Event, EventKind, RecursiveMode, Watcher}; use rsdsl_netlinkd::error::Result; use rsdsl_netlinkd::{addr, link, route}; use serde::{Deserialize, Serialize}; +use socket2::{Socket, Type}; use tun_tap::{Iface, Mode}; #[derive(Clone, Debug, Serialize, Deserialize)] @@ -39,6 +43,111 @@ impl From<Config> for UsableConfig { } } +fn tun2he(tun: Arc<Iface>) -> Result<()> { + let local = Ipv4Addr::new(10, 128, 10, 237); + let remote = Ipv4Addr::new(10, 128, 10, 185); + + let mut sock = Socket::new( + libc::AF_PACKET.into(), + Type::DGRAM, + Some(((libc::ETH_P_IPV6 as u16).to_be() as i32).into()), + )?; + + let mut buf = [0; 4 + 1492]; + loop { + let n = match tun.recv(&mut buf[20..]) { + Ok(v) => v, + Err(e) => { + println!("[6in4] tun2he warning: {}", e); + continue; + } + }; + let buf = &mut buf[..20 + n]; + + let ether_type = NE::read_u16(&buf[22..24]); + if ether_type != libc::ETH_P_IPV6 as u16 { + println!( + "[6in4] drop outbound non-ipv6 pkt, ethertype: 0x{:04x}", + ether_type + ); + continue; + } + + // Construct IP(v4) header. + buf[4] = 0b01000101; // Version = 4, IHL = 5 + buf[5] = 0; // DSCP / ECP = 0 + NE::write_u16(&mut buf[6..8], (n - 4 + 20) as u16); // Size = dynamic + NE::write_u16(&mut buf[8..10], 0); // ID = 0 + buf[10] = 0b01000000; // Flags = DF, Fragment Offset = 0... + buf[11] = 0; // Fragment Offset = ...0 + buf[12] = 64; // TTL = 64 + buf[13] = 41; // Protocol = 41 (6in4) + NE::write_u16(&mut buf[14..16], 0); // Checksum = 0 (computed later) + buf[16..20].copy_from_slice(&local.octets()); // Source IP Address = dynamic + buf[20..24].copy_from_slice(&remote.octets()); // Destination IP Address = HE + + let mut sum = 0i32; + for i in 0..10 { + let j = 4 + (i * 2); + sum += NE::read_u16(&buf[j..2 + j]) as i32; + } + + while sum >> 16 > 0 { + sum = (sum & 0xffff) + (sum >> 16); + } + + NE::write_u16(&mut buf[14..16], !(sum as u16)); + + match sock.write(&buf[4..]) { + Ok(sent) if sent != buf[4..].len() => println!( + "[6in4] tun2he warning: partial transmission ({} < {})", + sent, + buf[4..].len() + ), + Ok(_) => {} + Err(e) => println!("[6in4] tun2he warning: {}", e), + } + } +} + +fn he2tun(tun: Arc<Iface>) -> Result<()> { + let mut sock = Socket::new( + libc::AF_PACKET.into(), + Type::DGRAM, + Some(((libc::ETH_P_IP as u16).to_be() as i32).into()), + )?; + + let mut buf = [0; 4 + 1500]; + NE::write_u16(&mut buf[2..4], libc::ETH_P_IPV6 as u16); + + loop { + let n = match sock.read(&mut buf[4..]) { + Ok(v) => v, + Err(e) => { + println!("[6in4] he2tun warning: {}", e); + continue; + } + }; + let buf = &mut buf[..4 + n]; + + // Only process 6in4. + if buf[13] != 41 { + continue; + } + + NE::write_u16(&mut buf[22..24], libc::ETH_P_IPV6 as u16); + match tun.send(&buf[20..]) { + Ok(sent) if sent != buf.len() - 20 => println!( + "[6in4] he2tun warning: partial transmission ({} < {})", + sent, + buf.len() - 20 + ), + Ok(_) => {} + Err(e) => println!("[6in4] he2tun warning: {}", e), + } + } +} + fn main() -> Result<()> { let mut file = File::open("/data/he6in4.conf")?; let config: Config = serde_json::from_reader(&mut file)?; @@ -50,10 +159,21 @@ fn main() -> Result<()> { thread::sleep(Duration::from_secs(8)); } - let tun = Iface::new("he6in4", Mode::Tun)?; + let tun = Arc::new(Iface::new("he6in4", Mode::Tun)?); + let tun2 = tun.clone(); configure_tunnel(&config); + thread::spawn(move || match tun2he(tun2) { + Ok(_) => {} + Err(e) => panic!("tun2he error: {}", e), + }); + + thread::spawn(move || match he2tun(tun) { + Ok(_) => {} + Err(e) => panic!("he2tun error: {}", e), + }); + let mut watcher = notify::recommended_watcher(move |res: notify::Result<Event>| match res { Ok(event) => match event.kind { EventKind::Create(kind) if kind == CreateKind::File => { |