|
use std::{mem, os::raw::c_char}; |
|
|
|
use nix::{ |
|
fcntl::{open, OFlag}, |
|
ioctl_write_int, ioctl_write_ptr_bad, libc, |
|
sys::{ |
|
ioctl::ioctl_param_type, |
|
socket::{socket, AddressFamily, SockFlag, SockType, SockaddrIn}, |
|
stat::Mode, |
|
}, |
|
unistd::{read, write}, |
|
}; |
|
|
|
ioctl_write_int!(tunsetiff, b'T', 202); |
|
ioctl_write_ptr_bad!(siocsifaddr, libc::SIOCSIFADDR, libc::ifreq); |
|
ioctl_write_ptr_bad!(siocsifnetmask, libc::SIOCSIFNETMASK, libc::ifreq); |
|
ioctl_write_ptr_bad!(siocsifflags, libc::SIOCSIFFLAGS, libc::ifreq); |
|
|
|
fn setup() -> i32 { |
|
let fd = open("/dev/net/tun", OFlag::O_RDWR, Mode::empty()).unwrap(); |
|
|
|
let mut ifr_name: [c_char; libc::IF_NAMESIZE] = [0; libc::IF_NAMESIZE]; |
|
let name = b"tun0\0"; |
|
ifr_name[..name.len()].copy_from_slice(&name.map(|c| c as i8)[..]); |
|
|
|
// Create a TUN interface tun0 |
|
let ifru_flags = (libc::IFF_TUN | libc::IFF_NO_PI) as i16; |
|
let ifr_ifru = libc::__c_anonymous_ifr_ifru { ifru_flags }; |
|
let ifreq = libc::ifreq { ifr_name, ifr_ifru }; |
|
|
|
unsafe { tunsetiff(fd, &ifreq as *const libc::ifreq as ioctl_param_type) }.unwrap(); |
|
|
|
let sock = socket( |
|
AddressFamily::Inet, |
|
SockType::Datagram, |
|
SockFlag::empty(), |
|
None, |
|
) |
|
.unwrap(); |
|
|
|
// Assign 192.0.2.1 to tun0 |
|
let ifru_addr = SockaddrIn::new(192, 0, 2, 1, 0); |
|
let ifru_addr = unsafe { mem::transmute(ifru_addr) }; |
|
let ifr_ifru = libc::__c_anonymous_ifr_ifru { ifru_addr }; |
|
let ifreq = libc::ifreq { ifr_name, ifr_ifru }; |
|
|
|
unsafe { siocsifaddr(sock, &ifreq) }.unwrap(); |
|
|
|
// Set the network mask for tun0 to 255.255.255.0 (/24) |
|
let ifru_addr = SockaddrIn::new(255, 255, 255, 0, 0); |
|
let ifru_addr = unsafe { mem::transmute(ifru_addr) }; |
|
let ifr_ifru = libc::__c_anonymous_ifr_ifru { ifru_addr }; |
|
let ifreq = libc::ifreq { ifr_name, ifr_ifru }; |
|
|
|
unsafe { siocsifnetmask(sock, &ifreq) }.unwrap(); |
|
|
|
// Make the state of tun0 up |
|
let ifru_flags = libc::IFF_UP as i16; |
|
let ifr_ifru = libc::__c_anonymous_ifr_ifru { ifru_flags }; |
|
let ifreq = libc::ifreq { ifr_name, ifr_ifru }; |
|
|
|
unsafe { siocsifflags(sock, &ifreq) }.unwrap(); |
|
|
|
fd |
|
} |
|
|
|
fn main() { |
|
let fd = setup(); |
|
|
|
loop { |
|
let mut buf = [0u8; 128]; |
|
read(fd, &mut buf).unwrap(); |
|
|
|
// Debug |
|
println!("{:x?}", buf); |
|
|
|
// Swap the source IP address for the destination IP address |
|
for i in 12..16 { |
|
buf.swap(i, i + 4); |
|
} |
|
// Type |
|
// Echo Reply |
|
buf[20] = 0; |
|
|
|
// Set the checksum field to zero before computing a checksum |
|
buf[22] = 0; |
|
buf[23] = 0; |
|
|
|
let mut checksum: u32 = 0; |
|
for i in (20..buf.len()).step_by(2) { |
|
checksum += ((buf[i] as u32) << 8) + buf[i + 1] as u32; |
|
} |
|
while (checksum >> 16) != 0 { |
|
checksum = (checksum & 0xffff) + (checksum >> 16); |
|
} |
|
// one's complement |
|
checksum = !checksum; |
|
|
|
// Checksum |
|
buf[22] = (checksum >> 8) as u8; |
|
buf[23] = (checksum & 0xff) as u8; |
|
|
|
write(fd, &buf).unwrap(); |
|
} |
|
} |