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