1 // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 // SPDX-License-Identifier: Apache-2.0 3 // 4 // Portions Copyright 2017 The Chromium OS Authors. All rights reserved. 5 // Use of this source code is governed by a BSD-style license that can be 6 // found in the THIRD-PARTY file. 7 8 use std::fs::File; 9 use std::io::{Error as IoError, Read, Result as IoResult, Write}; 10 use std::net::{IpAddr, Ipv6Addr}; 11 use std::os::raw::*; 12 use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; 13 14 use thiserror::Error; 15 use vmm_sys_util::ioctl::{ioctl_with_mut_ref, ioctl_with_ref, ioctl_with_val}; 16 17 use super::{ 18 create_inet_socket, create_sockaddr, create_unix_socket, vnet_hdr_len, Error as NetUtilError, 19 MacAddr, 20 }; 21 use crate::mac::MAC_ADDR_LEN; 22 23 /// Maximum length of a network interface name in Linux, excluding any NUL byte. 24 /// 25 /// This corresponds to `IFNAMSIZ` in Linux [[0]]. 26 /// 27 /// [0]: https://elixir.bootlin.com/linux/v6.12/source/include/uapi/linux/if.h#L33 28 const MAX_INTERFACE_NAME_LEN: usize = 15; 29 30 #[derive(Error, Debug)] 31 pub enum Error { 32 #[error("Couldn't open /dev/net/tun")] 33 OpenTun(#[source] IoError), 34 #[error("Unable to configure tap interface")] 35 ConfigureTap(#[source] IoError), 36 #[error("Unable to retrieve features")] 37 GetFeatures(#[source] IoError), 38 #[error("Missing multiqueue support in the kernel")] 39 MultiQueueKernelSupport, 40 #[error("ioctl ({0}) failed: {1}")] 41 IoctlError(c_ulong, #[source] IoError), 42 #[error("Failed to create a socket")] 43 NetUtil(#[source] NetUtilError), 44 #[error("Interface name too long (max length is {MAX_INTERFACE_NAME_LEN}): {0}")] 45 IfnameTooLong(String), 46 #[error("Invalid interface name (does it exist?): {0}")] 47 InvalidIfname(String), 48 #[error("Error parsing MAC data")] 49 MacParsing(#[source] IoError), 50 #[error("Invalid netmask")] 51 InvalidNetmask, 52 } 53 54 pub type Result<T> = ::std::result::Result<T, Error>; 55 56 /// Handle for a network tap interface. 57 /// 58 /// For now, this simply wraps the file descriptor for the tap device so methods 59 /// can run ioctls on the interface. The tap interface fd will be closed when 60 /// Tap goes out of scope, and the kernel will clean up the interface 61 /// automatically. 62 #[derive(Debug)] 63 pub struct Tap { 64 tap_file: File, 65 if_name: Vec<u8>, 66 } 67 68 impl PartialEq for Tap { 69 fn eq(&self, other: &Tap) -> bool { 70 self.if_name == other.if_name 71 } 72 } 73 74 impl std::clone::Clone for Tap { 75 fn clone(&self) -> Self { 76 Tap { 77 tap_file: self.tap_file.try_clone().unwrap(), 78 if_name: self.if_name.clone(), 79 } 80 } 81 } 82 83 // Returns a byte vector representing the contents of a null terminated C string which 84 // contains if_name. 85 fn build_terminated_if_name(if_name: &str) -> Result<Vec<u8>> { 86 // Convert the string slice to bytes, and shadow the variable, 87 // since we no longer need the &str version. 88 let bytes = if_name.as_bytes(); 89 90 if bytes.len() > MAX_INTERFACE_NAME_LEN { 91 return Err(Error::IfnameTooLong(if_name.to_string())); 92 } 93 94 let mut terminated_if_name = vec![b'\0'; bytes.len() + 1]; 95 terminated_if_name[..bytes.len()].copy_from_slice(bytes); 96 97 Ok(terminated_if_name) 98 } 99 100 fn ipv6_mask_to_prefix(mask: Ipv6Addr) -> Result<u8> { 101 let mask = mask.segments(); 102 let mut iter = mask.iter(); 103 104 let mut prefix = 0; 105 for &segment in &mut iter { 106 if segment == 0xffff { 107 prefix += 16; 108 } else if segment == 0 { 109 break; 110 } else { 111 let prefix_bits = segment.leading_ones() as u8; 112 if segment << prefix_bits != 0 { 113 return Err(Error::InvalidNetmask); 114 } 115 116 prefix += prefix_bits; 117 break; 118 } 119 } 120 121 // Check that remaining bits are all unset 122 for &segment in iter { 123 if segment != 0 { 124 return Err(Error::InvalidNetmask); 125 } 126 } 127 128 Ok(prefix) 129 } 130 131 impl Tap { 132 unsafe fn ioctl_with_mut_ref<F: AsRawFd, T>(fd: &F, req: c_ulong, arg: &mut T) -> Result<()> { 133 let ret = ioctl_with_mut_ref(fd, req, arg); 134 if ret < 0 { 135 return Err(Error::IoctlError(req, IoError::last_os_error())); 136 } 137 138 Ok(()) 139 } 140 141 unsafe fn ioctl_with_ref<F: AsRawFd, T>(fd: &F, req: c_ulong, arg: &T) -> Result<()> { 142 let ret = ioctl_with_ref(fd, req, arg); 143 if ret < 0 { 144 return Err(Error::IoctlError(req, IoError::last_os_error())); 145 } 146 147 Ok(()) 148 } 149 150 unsafe fn ioctl_with_val<F: AsRawFd>(fd: &F, req: c_ulong, arg: c_ulong) -> Result<()> { 151 let ret = ioctl_with_val(fd, req, arg); 152 if ret < 0 { 153 return Err(Error::IoctlError(req, IoError::last_os_error())); 154 } 155 156 Ok(()) 157 } 158 159 pub fn open_named(if_name: &str, num_queue_pairs: usize, flags: Option<i32>) -> Result<Tap> { 160 let terminated_if_name = build_terminated_if_name(if_name)?; 161 162 // SAFETY: FFI call 163 let fd = unsafe { 164 // Open calls are safe because we give a constant null-terminated 165 // string and verify the result. 166 libc::open( 167 c"/dev/net/tun".as_ptr() as *const c_char, 168 flags.unwrap_or(libc::O_RDWR | libc::O_NONBLOCK | libc::O_CLOEXEC), 169 ) 170 }; 171 if fd < 0 { 172 return Err(Error::OpenTun(IoError::last_os_error())); 173 } 174 175 // SAFETY: We just checked that the fd is valid. 176 let tuntap = unsafe { File::from_raw_fd(fd) }; 177 178 // Let's validate some features before going any further. 179 // ioctl is safe since we call it with a valid tap fd and check the return 180 // value. 181 let mut features = 0; 182 // SAFETY: IOCTL with correct arguments 183 let ret = unsafe { ioctl_with_mut_ref(&tuntap, net_gen::TUNGETFEATURES(), &mut features) }; 184 if ret < 0 { 185 return Err(Error::GetFeatures(IoError::last_os_error())); 186 } 187 188 // Check if the user parameters match the kernel support for MQ 189 if (features & net_gen::IFF_MULTI_QUEUE == 0) && num_queue_pairs > 1 { 190 return Err(Error::MultiQueueKernelSupport); 191 } 192 193 // This is pretty messy because of the unions used by ifreq. Since we 194 // don't call as_mut on the same union field more than once, this block 195 // is safe. 196 let mut ifreq: net_gen::ifreq = Default::default(); 197 // SAFETY: see the comment above. 198 unsafe { 199 let ifrn_name = ifreq.ifr_ifrn.ifrn_name.as_mut(); 200 let name_slice = &mut ifrn_name[..terminated_if_name.len()]; 201 name_slice.copy_from_slice(terminated_if_name.as_slice()); 202 ifreq.ifr_ifru.ifru_flags = 203 (net_gen::IFF_TAP | net_gen::IFF_NO_PI | net_gen::IFF_VNET_HDR) as c_short; 204 if num_queue_pairs > 1 { 205 ifreq.ifr_ifru.ifru_flags |= net_gen::IFF_MULTI_QUEUE as c_short; 206 } 207 } 208 209 // SAFETY: ioctl is safe since we call it with a valid tap fd and check the return 210 // value. 211 let ret = unsafe { ioctl_with_mut_ref(&tuntap, net_gen::TUNSETIFF(), &mut ifreq) }; 212 if ret < 0 { 213 return Err(Error::ConfigureTap(IoError::last_os_error())); 214 } 215 216 // SAFETY: only the name is accessed, and it's cloned out. 217 let mut if_name = unsafe { ifreq.ifr_ifrn.ifrn_name }.to_vec(); 218 if_name.truncate(terminated_if_name.len() - 1); 219 Ok(Tap { 220 tap_file: tuntap, 221 if_name, 222 }) 223 } 224 225 /// Create a new tap interface. 226 pub fn new(num_queue_pairs: usize) -> Result<Tap> { 227 Self::open_named("vmtap%d", num_queue_pairs, None) 228 } 229 230 pub fn from_tap_fd(fd: RawFd, num_queue_pairs: usize) -> Result<Tap> { 231 // Ensure that the file is opened non-blocking, this is particularly 232 // needed when opened via the shell for macvtap. 233 // SAFETY: FFI call 234 let ret = unsafe { 235 let mut flags = libc::fcntl(fd, libc::F_GETFL); 236 flags |= libc::O_NONBLOCK; 237 libc::fcntl(fd, libc::F_SETFL, flags) 238 }; 239 if ret < 0 { 240 return Err(Error::ConfigureTap(IoError::last_os_error())); 241 } 242 243 // SAFETY: fd is a tap fd 244 let tap_file = unsafe { File::from_raw_fd(fd) }; 245 let mut ifreq: net_gen::ifreq = Default::default(); 246 247 // Get current config including name 248 // SAFETY: IOCTL with correct arguments 249 unsafe { Self::ioctl_with_mut_ref(&tap_file, net_gen::TUNGETIFF(), &mut ifreq)? }; 250 251 // SAFETY: We only access one field of the ifru union 252 let if_name = unsafe { ifreq.ifr_ifrn.ifrn_name }.to_vec(); 253 254 // Try and update flags. Depending on how the tap was created (macvtap 255 // or via open_named()) this might return -EEXIST so we just ignore that. 256 // SAFETY: access union fields 257 unsafe { 258 ifreq.ifr_ifru.ifru_flags = 259 (net_gen::IFF_TAP | net_gen::IFF_NO_PI | net_gen::IFF_VNET_HDR) as c_short; 260 if num_queue_pairs > 1 { 261 ifreq.ifr_ifru.ifru_flags |= net_gen::IFF_MULTI_QUEUE as c_short; 262 } 263 } 264 // SAFETY: IOCTL with correct arguments 265 let ret = unsafe { ioctl_with_mut_ref(&tap_file, net_gen::TUNSETIFF(), &mut ifreq) }; 266 if ret < 0 && IoError::last_os_error().raw_os_error().unwrap() != libc::EEXIST { 267 return Err(Error::ConfigureTap(IoError::last_os_error())); 268 } 269 270 let tap = Tap { tap_file, if_name }; 271 let vnet_hdr_size = vnet_hdr_len() as i32; 272 tap.set_vnet_hdr_size(vnet_hdr_size)?; 273 274 Ok(tap) 275 } 276 277 /// Set the host-side IP address for the tap interface. 278 pub fn set_ip_addr(&self, ip_addr: IpAddr, netmask: Option<IpAddr>) -> Result<()> { 279 let sock = create_inet_socket(ip_addr).map_err(Error::NetUtil)?; 280 281 let mut ifreq = self.get_ifreq(); 282 283 match ip_addr { 284 IpAddr::V4(addr) => { 285 let addr = create_sockaddr(addr); 286 287 ifreq.ifr_ifru.ifru_addr = addr; 288 289 // SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return. 290 unsafe { 291 Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFADDR as c_ulong, &ifreq)?; 292 } 293 294 if let Some(IpAddr::V4(mask)) = netmask { 295 ifreq.ifr_ifru.ifru_netmask = create_sockaddr(mask); 296 297 // SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return. 298 unsafe { 299 Self::ioctl_with_ref( 300 &sock, 301 net_gen::sockios::SIOCSIFNETMASK as c_ulong, 302 &ifreq, 303 )?; 304 } 305 }; 306 307 Ok(()) 308 } 309 IpAddr::V6(addr) => { 310 let ifindex = { 311 // SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return. 312 unsafe { 313 Self::ioctl_with_ref( 314 &sock, 315 net_gen::sockios::SIOCGIFINDEX as c_ulong, 316 &ifreq, 317 )?; 318 } 319 320 // SAFETY: ifru_ivalue contains the ifindex and is set by the previous ioctl 321 unsafe { 322 match ifreq.ifr_ifru.ifru_ivalue { 323 0 => { 324 let name = String::from_utf8_lossy(&self.if_name).to_string(); 325 return Err(Error::InvalidIfname(name)); 326 } 327 i => i, 328 } 329 } 330 }; 331 332 let prefixlen = match netmask { 333 Some(IpAddr::V6(netmask)) => ipv6_mask_to_prefix(netmask)?, 334 Some(IpAddr::V4(_)) => return Err(Error::InvalidNetmask), 335 None => 0, 336 }; 337 338 let ifreq = net_gen::in6_ifreq { 339 // SAFETY: addr can be safely transmuted to in6_addr 340 ifr6_addr: unsafe { 341 std::mem::transmute::<[u8; 16], net_gen::ipv6::in6_addr>(addr.octets()) 342 }, 343 ifr6_prefixlen: prefixlen as u32, 344 ifr6_ifindex: ifindex, 345 }; 346 347 // SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return. 348 unsafe { 349 Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFADDR as c_ulong, &ifreq) 350 } 351 } 352 } 353 } 354 355 /// Set mac addr for tap interface. 356 pub fn set_mac_addr(&self, addr: MacAddr) -> Result<()> { 357 // Checking if the mac address already matches the desired one 358 // is useful to avoid making the "set ioctl" in the case where 359 // the VMM is running without the privilege to do that. 360 // In practice this comes from a reboot after the configuration 361 // has been update with the kernel generated address. 362 if self.get_mac_addr()? == addr { 363 return Ok(()); 364 } 365 366 let sock = create_unix_socket().map_err(Error::NetUtil)?; 367 368 let mut ifreq = self.get_ifreq(); 369 370 // SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return. 371 unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFHWADDR as c_ulong, &ifreq)? }; 372 373 // SAFETY: We only access one field of the ifru union 374 unsafe { 375 let ifru_hwaddr = &mut ifreq.ifr_ifru.ifru_hwaddr; 376 for (i, v) in addr.get_bytes().iter().enumerate() { 377 ifru_hwaddr.sa_data[i] = *v as c_uchar; 378 } 379 } 380 381 // SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return. 382 unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFHWADDR as c_ulong, &ifreq) } 383 } 384 385 /// Get mac addr for tap interface. 386 pub fn get_mac_addr(&self) -> Result<MacAddr> { 387 let sock = create_unix_socket().map_err(Error::NetUtil)?; 388 389 let ifreq = self.get_ifreq(); 390 391 // SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return. 392 unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFHWADDR as c_ulong, &ifreq)? }; 393 394 // SAFETY: We only access one field of the ifru union 395 let addr = unsafe { 396 MacAddr::from_bytes(&ifreq.ifr_ifru.ifru_hwaddr.sa_data[0..MAC_ADDR_LEN]) 397 .map_err(Error::MacParsing)? 398 }; 399 Ok(addr) 400 } 401 402 #[cfg(not(fuzzing))] 403 pub fn mtu(&self) -> Result<i32> { 404 let sock = create_unix_socket().map_err(Error::NetUtil)?; 405 406 let ifreq = self.get_ifreq(); 407 408 // SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return. 409 unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFMTU as c_ulong, &ifreq)? }; 410 411 // SAFETY: access a union field 412 let mtu = unsafe { ifreq.ifr_ifru.ifru_mtu }; 413 414 Ok(mtu) 415 } 416 417 #[cfg(fuzzing)] 418 pub fn mtu(&self) -> Result<i32> { 419 // Consistent with the `virtio_devices::net::MIN_MTU` 420 Ok(1280) 421 } 422 423 pub fn set_mtu(&self, mtu: i32) -> Result<()> { 424 let sock = create_unix_socket().map_err(Error::NetUtil)?; 425 426 let mut ifreq = self.get_ifreq(); 427 ifreq.ifr_ifru.ifru_mtu = mtu; 428 429 // SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return. 430 unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFMTU as c_ulong, &ifreq) } 431 } 432 433 /// Set the offload flags for the tap interface. 434 pub fn set_offload(&self, flags: c_uint) -> Result<()> { 435 // SAFETY: ioctl is safe. Called with a valid tap fd, and we check the return. 436 unsafe { Self::ioctl_with_val(&self.tap_file, net_gen::TUNSETOFFLOAD(), flags as c_ulong) } 437 } 438 439 /// Enable the tap interface. 440 pub fn enable(&self) -> Result<()> { 441 let sock = create_unix_socket().map_err(Error::NetUtil)?; 442 443 let mut ifreq = self.get_ifreq(); 444 445 // SAFETY: IOCTL with correct arguments 446 unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFFLAGS as c_ulong, &ifreq)? }; 447 448 // If TAP device is already up don't try and enable it 449 // SAFETY: access a union field 450 let ifru_flags = unsafe { ifreq.ifr_ifru.ifru_flags }; 451 if ifru_flags & net_gen::net_device_flags_IFF_UP as i16 452 == net_gen::net_device_flags_IFF_UP as i16 453 { 454 return Ok(()); 455 } 456 457 ifreq.ifr_ifru.ifru_flags = net_gen::net_device_flags_IFF_UP as i16; 458 459 // SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return. 460 unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFFLAGS as c_ulong, &ifreq) } 461 } 462 463 /// Set the size of the vnet hdr. 464 pub fn set_vnet_hdr_size(&self, size: c_int) -> Result<()> { 465 // SAFETY: ioctl is safe. Called with a valid tap fd, and we check the return. 466 unsafe { Self::ioctl_with_ref(&self.tap_file, net_gen::TUNSETVNETHDRSZ(), &size) } 467 } 468 469 fn get_ifreq(&self) -> net_gen::ifreq { 470 let mut ifreq: net_gen::ifreq = Default::default(); 471 472 // This sets the name of the interface, which is the only entry 473 // in a single-field union. 474 // SAFETY: access union fields and we're sure the copy is okay. 475 unsafe { 476 let ifrn_name = ifreq.ifr_ifrn.ifrn_name.as_mut(); 477 let name_slice = &mut ifrn_name[..self.if_name.len()]; 478 name_slice.copy_from_slice(&self.if_name); 479 } 480 481 ifreq 482 } 483 484 pub fn get_if_name(&self) -> Vec<u8> { 485 self.if_name.clone() 486 } 487 488 #[cfg(fuzzing)] 489 pub fn new_for_fuzzing(tap_file: File, if_name: Vec<u8>) -> Self { 490 Tap { tap_file, if_name } 491 } 492 } 493 494 impl Read for Tap { 495 fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> { 496 self.tap_file.read(buf) 497 } 498 } 499 500 impl Write for Tap { 501 fn write(&mut self, buf: &[u8]) -> IoResult<usize> { 502 self.tap_file.write(buf) 503 } 504 505 fn flush(&mut self) -> IoResult<()> { 506 Ok(()) 507 } 508 } 509 510 impl AsRawFd for Tap { 511 fn as_raw_fd(&self) -> RawFd { 512 self.tap_file.as_raw_fd() 513 } 514 } 515 516 #[cfg(test)] 517 mod tests { 518 use std::net::Ipv4Addr; 519 use std::sync::{mpsc, LazyLock, Mutex}; 520 use std::time::Duration; 521 use std::{str, thread}; 522 523 use pnet::packet::ethernet::{EtherTypes, EthernetPacket, MutableEthernetPacket}; 524 use pnet::packet::ip::IpNextHeaderProtocols; 525 use pnet::packet::ipv4::{Ipv4Packet, MutableIpv4Packet}; 526 use pnet::packet::udp::{MutableUdpPacket, UdpPacket}; 527 use pnet::packet::{MutablePacket, Packet}; 528 use pnet::util::MacAddr; 529 use pnet_datalink::Channel::Ethernet; 530 use pnet_datalink::{DataLinkReceiver, DataLinkSender, NetworkInterface}; 531 532 use super::*; 533 534 static DATA_STRING: &str = "test for tap"; 535 static SUBNET_MASK: &str = "255.255.255.0"; 536 537 // We needed to have a mutex as a global variable, so we use a once cell for testing. The main 538 // potential problem, caused by tests being run in parallel by cargo, is creating different 539 // TAPs and trying to associate the same address, so we hide the IP address &str behind this 540 // mutex, more as a convention to remember to lock it at the very beginning of each function 541 // susceptible to this issue. Another variant is to use a different IP address per function, 542 // but we must remember to pick an unique one each time. 543 static TAP_IP_LOCK: LazyLock<Mutex<&'static str>> = 544 LazyLock::new(|| Mutex::new("192.168.241.1")); 545 546 // Describes the outcomes we are currently interested in when parsing a packet (we use 547 // an UDP packet for testing). 548 struct ParsedPkt<'a> { 549 eth: EthernetPacket<'a>, 550 ipv4: Option<Ipv4Packet<'a>>, 551 udp: Option<UdpPacket<'a>>, 552 } 553 554 impl<'a> ParsedPkt<'a> { 555 fn new(buf: &'a [u8]) -> Self { 556 let eth = EthernetPacket::new(buf).unwrap(); 557 let mut ipv4 = None; 558 let mut udp = None; 559 560 if eth.get_ethertype() == EtherTypes::Ipv4 { 561 let ipv4_start = 14; 562 ipv4 = Some(Ipv4Packet::new(&buf[ipv4_start..]).unwrap()); 563 564 // Hiding the old ipv4 variable for the rest of this block. 565 let ipv4 = Ipv4Packet::new(eth.payload()).unwrap(); 566 567 if ipv4.get_next_level_protocol() == IpNextHeaderProtocols::Udp { 568 // The value in header_length indicates the number of 32 bit words 569 // that make up the header, not the actual length in bytes. 570 let udp_start = ipv4_start + ipv4.get_header_length() as usize * 4; 571 udp = Some(UdpPacket::new(&buf[udp_start..]).unwrap()); 572 } 573 } 574 575 ParsedPkt { eth, ipv4, udp } 576 } 577 578 fn print(&self) { 579 print!( 580 "{} {} {} ", 581 self.eth.get_source(), 582 self.eth.get_destination(), 583 self.eth.get_ethertype() 584 ); 585 if let Some(ref ipv4) = self.ipv4 { 586 print!( 587 "{} {} {} ", 588 ipv4.get_source(), 589 ipv4.get_destination(), 590 ipv4.get_next_level_protocol() 591 ); 592 } 593 if let Some(ref udp) = self.udp { 594 print!( 595 "{} {} {}", 596 udp.get_source(), 597 udp.get_destination(), 598 str::from_utf8(udp.payload()).unwrap() 599 ); 600 } 601 println!(); 602 } 603 } 604 605 fn tap_name_to_string(tap: &Tap) -> String { 606 let null_pos = tap.if_name.iter().position(|x| *x == 0).unwrap(); 607 str::from_utf8(&tap.if_name[..null_pos]) 608 .unwrap() 609 .to_string() 610 } 611 612 // Given a buffer of appropriate size, this fills in the relevant fields based on the 613 // provided information. Payload refers to the UDP payload. 614 fn pnet_build_packet(buf: &mut [u8], dst_mac: MacAddr, payload: &[u8]) { 615 let mut eth = MutableEthernetPacket::new(buf).unwrap(); 616 eth.set_source(MacAddr::new(0x06, 0, 0, 0, 0, 0)); 617 eth.set_destination(dst_mac); 618 eth.set_ethertype(EtherTypes::Ipv4); 619 620 let mut ipv4 = MutableIpv4Packet::new(eth.payload_mut()).unwrap(); 621 ipv4.set_version(4); 622 ipv4.set_header_length(5); 623 ipv4.set_total_length(20 + 8 + payload.len() as u16); 624 ipv4.set_ttl(200); 625 ipv4.set_next_level_protocol(IpNextHeaderProtocols::Udp); 626 ipv4.set_source(Ipv4Addr::new(192, 168, 241, 1)); 627 ipv4.set_destination(Ipv4Addr::new(192, 168, 241, 2)); 628 629 let mut udp = MutableUdpPacket::new(ipv4.payload_mut()).unwrap(); 630 udp.set_source(1000); 631 udp.set_destination(1001); 632 udp.set_length(8 + payload.len() as u16); 633 udp.set_payload(payload); 634 } 635 636 // Sends a test packet on the interface named "ifname". 637 fn pnet_send_packet(ifname: String) { 638 let payload = DATA_STRING.as_bytes(); 639 640 // eth hdr + ip hdr + udp hdr + payload len 641 let buf_size = 14 + 20 + 8 + payload.len(); 642 643 let (mac, mut tx, _) = pnet_get_mac_tx_rx(ifname); 644 645 let res = tx.build_and_send(1, buf_size, &mut |buf| { 646 pnet_build_packet(buf, mac, payload); 647 }); 648 // Make sure build_and_send() -> Option<io::Result<()>> succeeds. 649 res.unwrap().unwrap(); 650 } 651 652 // For a given interface name, this returns a tuple that contains the MAC address of the 653 // interface, an object that can be used to send Ethernet frames, and a receiver of 654 // Ethernet frames arriving at the specified interface. 655 fn pnet_get_mac_tx_rx( 656 ifname: String, 657 ) -> (MacAddr, Box<dyn DataLinkSender>, Box<dyn DataLinkReceiver>) { 658 let interface_name_matches = |iface: &NetworkInterface| iface.name == ifname; 659 660 // Find the network interface with the provided name. 661 let interfaces = pnet_datalink::interfaces(); 662 let interface = interfaces.into_iter().find(interface_name_matches).unwrap(); 663 664 if let Ok(Ethernet(tx, rx)) = pnet_datalink::channel(&interface, Default::default()) { 665 (interface.mac.unwrap(), tx, rx) 666 } else { 667 panic!("datalink channel error or unhandled channel type"); 668 } 669 } 670 671 #[test] 672 fn test_tap_create() { 673 let _tap_ip_guard = TAP_IP_LOCK.lock().unwrap(); 674 675 let t = Tap::new(1).unwrap(); 676 println!("created tap: {t:?}"); 677 } 678 679 #[test] 680 fn test_tap_from_fd() { 681 let _tap_ip_guard = TAP_IP_LOCK.lock().unwrap(); 682 683 let orig_tap = Tap::new(1).unwrap(); 684 let fd = orig_tap.as_raw_fd(); 685 let _new_tap = Tap::from_tap_fd(fd, 1).unwrap(); 686 } 687 688 #[test] 689 fn test_tap_configure() { 690 // This should be the first thing to be called inside the function, so everything else 691 // is torn down by the time the mutex is automatically released. Also, we should 692 // explicitly bind the MutexGuard to a variable via let, the make sure it lives until 693 // the end of the function. 694 let tap_ip_guard = TAP_IP_LOCK.lock().unwrap(); 695 696 let tap = Tap::new(1).unwrap(); 697 let ip_addr = IpAddr::V4((*tap_ip_guard).parse().unwrap()); 698 let netmask = IpAddr::V4(SUBNET_MASK.parse().unwrap()); 699 700 tap.set_ip_addr(ip_addr, Some(netmask)).unwrap(); 701 } 702 703 #[test] 704 fn test_tap_configure_ipv6() { 705 let tap_ip6_lock: Mutex<&'static str> = Mutex::new("2001:db8:85a3::8a2e:370:7334"); 706 let tap_ip6_guard = tap_ip6_lock.lock().unwrap(); 707 708 let tap = Tap::new(1).unwrap(); 709 let ip_addr = IpAddr::V6((*tap_ip6_guard).parse().unwrap()); 710 let netmask = IpAddr::V6("ffff:ffff::".parse().unwrap()); 711 712 tap.set_ip_addr(ip_addr, Some(netmask)).unwrap(); 713 } 714 715 #[test] 716 fn test_set_options() { 717 let _tap_ip_guard = TAP_IP_LOCK.lock().unwrap(); 718 719 // This line will fail to provide an initialized FD if the test is not run as root. 720 let tap = Tap::new(1).unwrap(); 721 tap.set_vnet_hdr_size(16).unwrap(); 722 tap.set_offload(0).unwrap(); 723 } 724 725 #[test] 726 fn test_tap_enable() { 727 let _tap_ip_guard = TAP_IP_LOCK.lock().unwrap(); 728 729 let tap = Tap::new(1).unwrap(); 730 tap.enable().unwrap(); 731 } 732 733 #[test] 734 fn test_raw_fd() { 735 let _tap_ip_guard = TAP_IP_LOCK.lock().unwrap(); 736 737 let tap = Tap::new(1).unwrap(); 738 assert_eq!(tap.as_raw_fd(), tap.tap_file.as_raw_fd()); 739 } 740 741 #[test] 742 fn test_read() { 743 let tap_ip_guard = TAP_IP_LOCK.lock().unwrap(); 744 745 let mut tap = Tap::new(1).unwrap(); 746 let ip_addr = IpAddr::V4((*tap_ip_guard).parse().unwrap()); 747 let netmask = IpAddr::V4(SUBNET_MASK.parse().unwrap()); 748 tap.set_ip_addr(ip_addr, Some(netmask)).unwrap(); 749 tap.enable().unwrap(); 750 751 // Send a packet to the interface. We expect to be able to receive it on the associated fd. 752 pnet_send_packet(tap_name_to_string(&tap)); 753 754 let mut buf = [0u8; 4096]; 755 756 let mut found_packet_sz = None; 757 758 // In theory, this could actually loop forever if something keeps sending data through the 759 // tap interface, but it's highly unlikely. 760 while found_packet_sz.is_none() { 761 let size = tap.read(&mut buf).unwrap(); 762 763 // We skip the first 10 bytes because the IFF_VNET_HDR flag is set when the interface 764 // is created, and the legacy header is 10 bytes long without a certain flag which 765 // is not set in Tap::new(). 766 let eth_bytes = &buf[10..size]; 767 768 let packet = EthernetPacket::new(eth_bytes).unwrap(); 769 if packet.get_ethertype() != EtherTypes::Ipv4 { 770 // not an IPv4 packet 771 continue; 772 } 773 774 let ipv4_bytes = ð_bytes[14..]; 775 let packet = Ipv4Packet::new(ipv4_bytes).unwrap(); 776 777 // Our packet should carry an UDP payload, and not contain IP options. 778 if packet.get_next_level_protocol() != IpNextHeaderProtocols::Udp 779 && packet.get_header_length() != 5 780 { 781 continue; 782 } 783 784 let udp_bytes = &ipv4_bytes[20..]; 785 786 let udp_len = UdpPacket::new(udp_bytes).unwrap().get_length() as usize; 787 788 // Skip the header bytes. 789 let inner_string = str::from_utf8(&udp_bytes[8..udp_len]).unwrap(); 790 791 if inner_string.eq(DATA_STRING) { 792 found_packet_sz = Some(size); 793 break; 794 } 795 } 796 797 assert!(found_packet_sz.is_some()); 798 } 799 800 #[test] 801 fn test_write() { 802 let tap_ip_guard = TAP_IP_LOCK.lock().unwrap(); 803 804 let mut tap = Tap::new(1).unwrap(); 805 let ip_addr = IpAddr::V4((*tap_ip_guard).parse().unwrap()); 806 let netmask = IpAddr::V4(SUBNET_MASK.parse().unwrap()); 807 tap.set_ip_addr(ip_addr, Some(netmask)).unwrap(); 808 tap.enable().unwrap(); 809 810 let (mac, _, mut rx) = pnet_get_mac_tx_rx(tap_name_to_string(&tap)); 811 812 let payload = DATA_STRING.as_bytes(); 813 814 // vnet hdr + eth hdr + ip hdr + udp hdr + payload len 815 let buf_size = 10 + 14 + 20 + 8 + payload.len(); 816 817 let mut buf = vec![0u8; buf_size]; 818 // leave the vnet hdr as is 819 pnet_build_packet(&mut buf[10..], mac, payload); 820 821 tap.write_all(&buf).unwrap(); 822 tap.flush().unwrap(); 823 824 let (channel_tx, channel_rx) = mpsc::channel(); 825 826 // We use a separate thread to wait for the test packet because the API exposed by pnet is 827 // blocking. This thread will be killed when the main thread exits. 828 let _handle = thread::spawn(move || loop { 829 let buf = rx.next().unwrap(); 830 let p = ParsedPkt::new(buf); 831 p.print(); 832 833 if let Some(ref udp) = p.udp { 834 if payload == udp.payload() { 835 channel_tx.send(true).unwrap(); 836 break; 837 } 838 } 839 }); 840 841 // We wait for at most SLEEP_MILLIS * SLEEP_ITERS milliseconds for the reception of the 842 // test packet to be detected. 843 static SLEEP_MILLIS: u64 = 500; 844 static SLEEP_ITERS: u32 = 6; 845 846 let mut found_test_packet = false; 847 848 for _ in 0..SLEEP_ITERS { 849 thread::sleep(Duration::from_millis(SLEEP_MILLIS)); 850 if let Ok(true) = channel_rx.try_recv() { 851 found_test_packet = true; 852 break; 853 } 854 } 855 856 assert!(found_test_packet); 857 } 858 } 859