Add support for TUN interfaces.
parent
b6220a04c8
commit
9e3b373e36
|
@ -27,7 +27,7 @@ jobs:
|
|||
|
||||
# Test features chosen to be as orthogonal as possible.
|
||||
- std medium-ethernet phy-raw_socket proto-ipv6 socket-udp
|
||||
- std medium-ethernet phy-tap_interface proto-ipv6 socket-udp
|
||||
- std medium-ethernet phy-tuntap_interface proto-ipv6 socket-udp
|
||||
- std medium-ethernet proto-ipv4 proto-igmp socket-raw
|
||||
- std medium-ethernet proto-ipv4 socket-udp socket-tcp
|
||||
- std medium-ethernet proto-ipv4 proto-dhcpv4 socket-udp
|
||||
|
|
24
Cargo.toml
24
Cargo.toml
|
@ -34,11 +34,11 @@ alloc = ["managed/alloc"]
|
|||
verbose = []
|
||||
"medium-ethernet" = ["socket"]
|
||||
"medium-ip" = ["socket"]
|
||||
"phy-raw_socket" = ["std", "libc", "ethernet"]
|
||||
"phy-tap_interface" = ["std", "libc", "ethernet"]
|
||||
"phy-raw_socket" = ["std", "libc", "medium-ethernet"]
|
||||
"phy-tuntap_interface" = ["std", "libc", "medium-ethernet"]
|
||||
"proto-ipv4" = []
|
||||
"proto-igmp" = ["proto-ipv4"]
|
||||
"proto-dhcpv4" = ["proto-ipv4", "socket-raw", "ethernet"]
|
||||
"proto-dhcpv4" = ["proto-ipv4", "socket-raw", "medium-ethernet"]
|
||||
"proto-ipv6" = []
|
||||
"socket" = []
|
||||
"socket-raw" = ["socket"]
|
||||
|
@ -49,7 +49,7 @@ verbose = []
|
|||
default = [
|
||||
"std", "log", # needed for `cargo test --no-default-features --features default` :/
|
||||
"medium-ethernet", "medium-ip",
|
||||
"phy-raw_socket", "phy-tap_interface",
|
||||
"phy-raw_socket", "phy-tuntap_interface",
|
||||
"proto-ipv4", "proto-igmp", "proto-dhcpv4", "proto-ipv6",
|
||||
"socket-raw", "socket-icmp", "socket-udp", "socket-tcp",
|
||||
"async"
|
||||
|
@ -69,35 +69,35 @@ required-features = ["std", "phy-raw_socket", "proto-ipv4"]
|
|||
|
||||
[[example]]
|
||||
name = "httpclient"
|
||||
required-features = ["std", "phy-tap_interface", "proto-ipv4", "proto-ipv6", "socket-tcp"]
|
||||
required-features = ["std", "medium-ethernet", "medium-ip", "phy-tuntap_interface", "proto-ipv4", "proto-ipv6", "socket-tcp"]
|
||||
|
||||
[[example]]
|
||||
name = "ping"
|
||||
required-features = ["std", "phy-tap_interface", "proto-ipv4", "proto-ipv6", "socket-icmp"]
|
||||
required-features = ["std", "medium-ethernet", "medium-ip", "phy-tuntap_interface", "proto-ipv4", "proto-ipv6", "socket-icmp"]
|
||||
|
||||
[[example]]
|
||||
name = "server"
|
||||
required-features = ["std", "phy-tap_interface", "proto-ipv4", "socket-tcp", "socket-udp"]
|
||||
required-features = ["std", "medium-ethernet", "medium-ip", "phy-tuntap_interface", "proto-ipv4", "socket-tcp", "socket-udp"]
|
||||
|
||||
[[example]]
|
||||
name = "client"
|
||||
required-features = ["std", "phy-tap_interface", "proto-ipv4", "socket-tcp", "socket-udp"]
|
||||
required-features = ["std", "medium-ethernet", "medium-ip", "phy-tuntap_interface", "proto-ipv4", "socket-tcp", "socket-udp"]
|
||||
|
||||
[[example]]
|
||||
name = "loopback"
|
||||
required-features = ["log", "proto-ipv4", "socket-tcp"]
|
||||
required-features = ["log", "medium-ethernet", "proto-ipv4", "socket-tcp"]
|
||||
|
||||
[[example]]
|
||||
name = "multicast"
|
||||
required-features = ["std", "phy-tap_interface", "proto-ipv4", "proto-igmp", "socket-udp"]
|
||||
required-features = ["std", "medium-ethernet", "medium-ip", "phy-tuntap_interface", "proto-ipv4", "proto-igmp", "socket-udp"]
|
||||
|
||||
[[example]]
|
||||
name = "benchmark"
|
||||
required-features = ["std", "phy-tap_interface", "proto-ipv4", "socket-raw", "socket-udp"]
|
||||
required-features = ["std", "medium-ethernet", "medium-ip", "phy-tuntap_interface", "proto-ipv4", "socket-raw", "socket-udp"]
|
||||
|
||||
[[example]]
|
||||
name = "dhcp_client"
|
||||
required-features = ["std", "phy-tap_interface", "proto-ipv4", "proto-dhcpv4", "socket-raw"]
|
||||
required-features = ["std", "medium-ethernet", "medium-ip", "phy-tuntap_interface", "proto-ipv4", "proto-dhcpv4", "socket-raw"]
|
||||
|
||||
[profile.release]
|
||||
debug = 2
|
||||
|
|
|
@ -170,9 +170,9 @@ or `BufWriter` is used, which are of course not available on heap-less systems.
|
|||
|
||||
This feature is disabled by default.
|
||||
|
||||
### Features `phy-raw_socket` and `phy-tap_interface`
|
||||
### Features `phy-raw_socket` and `phy-tuntap_interface`
|
||||
|
||||
Enable `smoltcp::phy::RawSocket` and `smoltcp::phy::TapInterface`, respectively.
|
||||
Enable `smoltcp::phy::RawSocket` and `smoltcp::phy::TunTapInterface`, respectively.
|
||||
|
||||
These features are enabled by default.
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ use std::net::TcpStream;
|
|||
use std::os::unix::io::AsRawFd;
|
||||
use log::debug;
|
||||
|
||||
use smoltcp::phy::wait as phy_wait;
|
||||
use smoltcp::phy::{Device, Medium, wait as phy_wait};
|
||||
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr};
|
||||
use smoltcp::iface::{NeighborCache, InterfaceBuilder};
|
||||
use smoltcp::socket::SocketSet;
|
||||
|
@ -62,12 +62,12 @@ fn main() {
|
|||
utils::setup_logging("info");
|
||||
|
||||
let (mut opts, mut free) = utils::create_options();
|
||||
utils::add_tap_options(&mut opts, &mut free);
|
||||
utils::add_tuntap_options(&mut opts, &mut free);
|
||||
utils::add_middleware_options(&mut opts, &mut free);
|
||||
free.push("MODE");
|
||||
|
||||
let mut matches = utils::parse_options(&opts, free);
|
||||
let device = utils::parse_tap_options(&mut matches);
|
||||
let device = utils::parse_tuntap_options(&mut matches);
|
||||
let fd = device.as_raw_fd();
|
||||
let device = utils::parse_middleware_options(&mut matches, device, /*loopback=*/false);
|
||||
let mode = match matches.free[0].as_ref() {
|
||||
|
@ -90,11 +90,15 @@ fn main() {
|
|||
|
||||
let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]);
|
||||
let ip_addrs = [IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24)];
|
||||
let mut iface = InterfaceBuilder::new(device)
|
||||
let medium = device.capabilities().medium;
|
||||
let mut builder = InterfaceBuilder::new(device)
|
||||
.ip_addrs(ip_addrs);
|
||||
if medium == Medium::Ethernet {
|
||||
builder = builder
|
||||
.ethernet_addr(ethernet_addr)
|
||||
.neighbor_cache(neighbor_cache)
|
||||
.ip_addrs(ip_addrs)
|
||||
.finalize();
|
||||
.neighbor_cache(neighbor_cache);
|
||||
}
|
||||
let mut iface = builder.finalize();
|
||||
|
||||
let mut sockets = SocketSet::new(vec![]);
|
||||
let tcp1_handle = sockets.add(tcp1_socket);
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::collections::BTreeMap;
|
|||
use std::os::unix::io::AsRawFd;
|
||||
use log::debug;
|
||||
|
||||
use smoltcp::phy::wait as phy_wait;
|
||||
use smoltcp::phy::{Device, Medium, wait as phy_wait};
|
||||
use smoltcp::wire::{EthernetAddress, Ipv4Address, IpAddress, IpCidr};
|
||||
use smoltcp::iface::{NeighborCache, InterfaceBuilder, Routes};
|
||||
use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer};
|
||||
|
@ -15,13 +15,14 @@ fn main() {
|
|||
utils::setup_logging("");
|
||||
|
||||
let (mut opts, mut free) = utils::create_options();
|
||||
utils::add_tap_options(&mut opts, &mut free);
|
||||
utils::add_tuntap_options(&mut opts, &mut free);
|
||||
utils::add_middleware_options(&mut opts, &mut free);
|
||||
free.push("ADDRESS");
|
||||
free.push("PORT");
|
||||
|
||||
let mut matches = utils::parse_options(&opts, free);
|
||||
let device = utils::parse_tap_options(&mut matches);
|
||||
let device = utils::parse_tuntap_options(&mut matches);
|
||||
|
||||
let fd = device.as_raw_fd();
|
||||
let device = utils::parse_middleware_options(&mut matches, device, /*loopback=*/false);
|
||||
let address = IpAddress::from_str(&matches.free[0]).expect("invalid address format");
|
||||
|
@ -39,12 +40,17 @@ fn main() {
|
|||
let mut routes_storage = [None; 1];
|
||||
let mut routes = Routes::new(&mut routes_storage[..]);
|
||||
routes.add_default_ipv4_route(default_v4_gw).unwrap();
|
||||
let mut iface = InterfaceBuilder::new(device)
|
||||
.ethernet_addr(ethernet_addr)
|
||||
.neighbor_cache(neighbor_cache)
|
||||
|
||||
let medium = device.capabilities().medium;
|
||||
let mut builder = InterfaceBuilder::new(device)
|
||||
.ip_addrs(ip_addrs)
|
||||
.routes(routes)
|
||||
.finalize();
|
||||
.routes(routes);
|
||||
if medium == Medium::Ethernet {
|
||||
builder = builder
|
||||
.ethernet_addr(ethernet_addr)
|
||||
.neighbor_cache(neighbor_cache);
|
||||
}
|
||||
let mut iface = builder.finalize();
|
||||
|
||||
let mut sockets = SocketSet::new(vec![]);
|
||||
let tcp_handle = sockets.add(tcp_socket);
|
||||
|
|
|
@ -3,7 +3,7 @@ mod utils;
|
|||
|
||||
use std::collections::BTreeMap;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use smoltcp::phy::wait as phy_wait;
|
||||
use smoltcp::phy::{Device, Medium, wait as phy_wait};
|
||||
use smoltcp::wire::{EthernetAddress, Ipv4Address, IpCidr, Ipv4Cidr};
|
||||
use smoltcp::iface::{NeighborCache, InterfaceBuilder, Routes};
|
||||
use smoltcp::socket::{SocketSet, RawSocketBuffer, RawPacketMetadata};
|
||||
|
@ -15,11 +15,11 @@ fn main() {
|
|||
utils::setup_logging("");
|
||||
|
||||
let (mut opts, mut free) = utils::create_options();
|
||||
utils::add_tap_options(&mut opts, &mut free);
|
||||
utils::add_tuntap_options(&mut opts, &mut free);
|
||||
utils::add_middleware_options(&mut opts, &mut free);
|
||||
|
||||
let mut matches = utils::parse_options(&opts, free);
|
||||
let device = utils::parse_tap_options(&mut matches);
|
||||
let device = utils::parse_tuntap_options(&mut matches);
|
||||
let fd = device.as_raw_fd();
|
||||
let device = utils::parse_middleware_options(&mut matches, device, /*loopback=*/false);
|
||||
|
||||
|
@ -28,12 +28,17 @@ fn main() {
|
|||
let ip_addrs = [IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 0)];
|
||||
let mut routes_storage = [None; 1];
|
||||
let routes = Routes::new(&mut routes_storage[..]);
|
||||
let mut iface = InterfaceBuilder::new(device)
|
||||
.ethernet_addr(ethernet_addr)
|
||||
.neighbor_cache(neighbor_cache)
|
||||
|
||||
let medium = device.capabilities().medium;
|
||||
let mut builder = InterfaceBuilder::new(device)
|
||||
.ip_addrs(ip_addrs)
|
||||
.routes(routes)
|
||||
.finalize();
|
||||
.routes(routes);
|
||||
if medium == Medium::Ethernet {
|
||||
builder = builder
|
||||
.ethernet_addr(ethernet_addr)
|
||||
.neighbor_cache(neighbor_cache);
|
||||
}
|
||||
let mut iface = builder.finalize();
|
||||
|
||||
let mut sockets = SocketSet::new(vec![]);
|
||||
let dhcp_rx_buffer = RawSocketBuffer::new(
|
||||
|
|
|
@ -6,7 +6,7 @@ use std::os::unix::io::AsRawFd;
|
|||
use url::Url;
|
||||
use log::debug;
|
||||
|
||||
use smoltcp::phy::wait as phy_wait;
|
||||
use smoltcp::phy::{Device, Medium, wait as phy_wait};
|
||||
use smoltcp::wire::{EthernetAddress, Ipv4Address, Ipv6Address, IpAddress, IpCidr};
|
||||
use smoltcp::iface::{NeighborCache, InterfaceBuilder, Routes};
|
||||
use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer};
|
||||
|
@ -16,13 +16,13 @@ fn main() {
|
|||
utils::setup_logging("");
|
||||
|
||||
let (mut opts, mut free) = utils::create_options();
|
||||
utils::add_tap_options(&mut opts, &mut free);
|
||||
utils::add_tuntap_options(&mut opts, &mut free);
|
||||
utils::add_middleware_options(&mut opts, &mut free);
|
||||
free.push("ADDRESS");
|
||||
free.push("URL");
|
||||
|
||||
let mut matches = utils::parse_options(&opts, free);
|
||||
let device = utils::parse_tap_options(&mut matches);
|
||||
let device = utils::parse_tuntap_options(&mut matches);
|
||||
let fd = device.as_raw_fd();
|
||||
let device = utils::parse_middleware_options(&mut matches, device, /*loopback=*/false);
|
||||
let address = IpAddress::from_str(&matches.free[0]).expect("invalid address format");
|
||||
|
@ -45,12 +45,17 @@ fn main() {
|
|||
let mut routes = Routes::new(&mut routes_storage[..]);
|
||||
routes.add_default_ipv4_route(default_v4_gw).unwrap();
|
||||
routes.add_default_ipv6_route(default_v6_gw).unwrap();
|
||||
let mut iface = InterfaceBuilder::new(device)
|
||||
.ethernet_addr(ethernet_addr)
|
||||
.neighbor_cache(neighbor_cache)
|
||||
|
||||
let medium = device.capabilities().medium;
|
||||
let mut builder = InterfaceBuilder::new(device)
|
||||
.ip_addrs(ip_addrs)
|
||||
.routes(routes)
|
||||
.finalize();
|
||||
.routes(routes);
|
||||
if medium == Medium::Ethernet {
|
||||
builder = builder
|
||||
.ethernet_addr(ethernet_addr)
|
||||
.neighbor_cache(neighbor_cache);
|
||||
}
|
||||
let mut iface = builder.finalize();
|
||||
|
||||
let mut sockets = SocketSet::new(vec![]);
|
||||
let tcp_handle = sockets.add(tcp_socket);
|
||||
|
|
|
@ -20,11 +20,11 @@ fn main() {
|
|||
utils::setup_logging("warn");
|
||||
|
||||
let (mut opts, mut free) = utils::create_options();
|
||||
utils::add_tap_options(&mut opts, &mut free);
|
||||
utils::add_tuntap_options(&mut opts, &mut free);
|
||||
utils::add_middleware_options(&mut opts, &mut free);
|
||||
|
||||
let mut matches = utils::parse_options(&opts, free);
|
||||
let device = utils::parse_tap_options(&mut matches);
|
||||
let device = utils::parse_tuntap_options(&mut matches);
|
||||
let fd = device.as_raw_fd();
|
||||
let device = utils::parse_middleware_options(&mut matches,
|
||||
device,
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::collections::HashMap;
|
|||
use log::debug;
|
||||
use byteorder::{ByteOrder, NetworkEndian};
|
||||
|
||||
use smoltcp::time::{Duration, Instant};
|
||||
use smoltcp::{phy::Medium, time::{Duration, Instant}};
|
||||
use smoltcp::phy::Device;
|
||||
use smoltcp::phy::wait as phy_wait;
|
||||
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr,
|
||||
|
@ -55,7 +55,7 @@ fn main() {
|
|||
utils::setup_logging("warn");
|
||||
|
||||
let (mut opts, mut free) = utils::create_options();
|
||||
utils::add_tap_options(&mut opts, &mut free);
|
||||
utils::add_tuntap_options(&mut opts, &mut free);
|
||||
utils::add_middleware_options(&mut opts, &mut free);
|
||||
opts.optopt("c", "count", "Amount of echo request packets to send (default: 4)", "COUNT");
|
||||
opts.optopt("i", "interval",
|
||||
|
@ -66,7 +66,7 @@ fn main() {
|
|||
free.push("ADDRESS");
|
||||
|
||||
let mut matches = utils::parse_options(&opts, free);
|
||||
let device = utils::parse_tap_options(&mut matches);
|
||||
let device = utils::parse_tuntap_options(&mut matches);
|
||||
let fd = device.as_raw_fd();
|
||||
let device = utils::parse_middleware_options(&mut matches, device, /*loopback=*/false);
|
||||
let device_caps = device.capabilities();
|
||||
|
@ -98,12 +98,17 @@ fn main() {
|
|||
let mut routes = Routes::new(&mut routes_storage[..]);
|
||||
routes.add_default_ipv4_route(default_v4_gw).unwrap();
|
||||
routes.add_default_ipv6_route(default_v6_gw).unwrap();
|
||||
let mut iface = InterfaceBuilder::new(device)
|
||||
.ethernet_addr(ethernet_addr)
|
||||
|
||||
let medium = device.capabilities().medium;
|
||||
let mut builder = InterfaceBuilder::new(device)
|
||||
.ip_addrs(ip_addrs)
|
||||
.routes(routes)
|
||||
.neighbor_cache(neighbor_cache)
|
||||
.finalize();
|
||||
.routes(routes);
|
||||
if medium == Medium::Ethernet {
|
||||
builder = builder
|
||||
.ethernet_addr(ethernet_addr)
|
||||
.neighbor_cache(neighbor_cache);
|
||||
}
|
||||
let mut iface = builder.finalize();
|
||||
|
||||
let mut sockets = SocketSet::new(vec![]);
|
||||
let icmp_handle = sockets.add(icmp_socket);
|
||||
|
|
|
@ -6,7 +6,7 @@ use std::fmt::Write;
|
|||
use std::os::unix::io::AsRawFd;
|
||||
use log::debug;
|
||||
|
||||
use smoltcp::phy::wait as phy_wait;
|
||||
use smoltcp::phy::{Device, Medium, wait as phy_wait};
|
||||
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr};
|
||||
use smoltcp::iface::{NeighborCache, InterfaceBuilder};
|
||||
use smoltcp::socket::SocketSet;
|
||||
|
@ -18,11 +18,11 @@ fn main() {
|
|||
utils::setup_logging("");
|
||||
|
||||
let (mut opts, mut free) = utils::create_options();
|
||||
utils::add_tap_options(&mut opts, &mut free);
|
||||
utils::add_tuntap_options(&mut opts, &mut free);
|
||||
utils::add_middleware_options(&mut opts, &mut free);
|
||||
|
||||
let mut matches = utils::parse_options(&opts, free);
|
||||
let device = utils::parse_tap_options(&mut matches);
|
||||
let device = utils::parse_tuntap_options(&mut matches);
|
||||
let fd = device.as_raw_fd();
|
||||
let device = utils::parse_middleware_options(&mut matches, device, /*loopback=*/false);
|
||||
|
||||
|
@ -54,11 +54,16 @@ fn main() {
|
|||
IpCidr::new(IpAddress::v6(0xfdaa, 0, 0, 0, 0, 0, 0, 1), 64),
|
||||
IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64)
|
||||
];
|
||||
let mut iface = InterfaceBuilder::new(device)
|
||||
|
||||
let medium = device.capabilities().medium;
|
||||
let mut builder = InterfaceBuilder::new(device)
|
||||
.ip_addrs(ip_addrs);
|
||||
if medium == Medium::Ethernet {
|
||||
builder = builder
|
||||
.ethernet_addr(ethernet_addr)
|
||||
.neighbor_cache(neighbor_cache)
|
||||
.ip_addrs(ip_addrs)
|
||||
.finalize();
|
||||
.neighbor_cache(neighbor_cache);
|
||||
}
|
||||
let mut iface = builder.finalize();
|
||||
|
||||
let mut sockets = SocketSet::new(vec![]);
|
||||
let udp_handle = sockets.add(udp_socket);
|
||||
|
|
|
@ -14,9 +14,9 @@ use log::{Level, LevelFilter, trace};
|
|||
use env_logger::Builder;
|
||||
use getopts::{Options, Matches};
|
||||
|
||||
use smoltcp::phy::{Device, EthernetTracer, FaultInjector};
|
||||
#[cfg(feature = "phy-tap_interface")]
|
||||
use smoltcp::phy::TapInterface;
|
||||
use smoltcp::phy::{Device, EthernetTracer, FaultInjector, Medium};
|
||||
#[cfg(feature = "phy-tuntap_interface")]
|
||||
use smoltcp::phy::TunTapInterface;
|
||||
use smoltcp::phy::{PcapWriter, PcapSink, PcapMode, PcapLinkType};
|
||||
use smoltcp::phy::RawSocket;
|
||||
use smoltcp::time::{Duration, Instant};
|
||||
|
@ -77,14 +77,20 @@ pub fn parse_options(options: &Options, free: Vec<&str>) -> Matches {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn add_tap_options(_opts: &mut Options, free: &mut Vec<&str>) {
|
||||
free.push("INTERFACE");
|
||||
pub fn add_tuntap_options(opts: &mut Options, _free: &mut Vec<&str>) {
|
||||
opts.optopt("", "tun", "TUN interface to use", "tun0");
|
||||
opts.optopt("", "tap", "TAP interface to use", "tap0");
|
||||
}
|
||||
|
||||
#[cfg(feature = "phy-tap_interface")]
|
||||
pub fn parse_tap_options(matches: &mut Matches) -> TapInterface {
|
||||
let interface = matches.free.remove(0);
|
||||
TapInterface::new(&interface).unwrap()
|
||||
#[cfg(feature = "phy-tuntap_interface")]
|
||||
pub fn parse_tuntap_options(matches: &mut Matches) -> TunTapInterface {
|
||||
let tun = matches.opt_str("tun");
|
||||
let tap = matches.opt_str("tap");
|
||||
match(tun,tap) {
|
||||
(Some(tun), None) => TunTapInterface::new(&tun, Medium::Ip).unwrap(),
|
||||
(None, Some(tap)) => TunTapInterface::new(&tap, Medium::Ethernet).unwrap(),
|
||||
_ => panic!("You must specify exactly one of --tun or --tap"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_raw_socket_options(matches: &mut Matches) -> RawSocket {
|
||||
|
|
|
@ -8,7 +8,7 @@ and implementations of it:
|
|||
* _middleware_ [Tracer](struct.Tracer.html) and
|
||||
[FaultInjector](struct.FaultInjector.html), to facilitate debugging;
|
||||
* _adapters_ [RawSocket](struct.RawSocket.html) and
|
||||
[TapInterface](struct.TapInterface.html), to transmit and receive frames
|
||||
[TunTapInterface](struct.TunTapInterface.html), to transmit and receive frames
|
||||
on the host OS.
|
||||
*/
|
||||
#![cfg_attr(feature = "medium-ethernet", doc = r##"
|
||||
|
@ -89,7 +89,7 @@ impl<'a> phy::TxToken for StmPhyTxToken<'a> {
|
|||
use crate::Result;
|
||||
use crate::time::Instant;
|
||||
|
||||
#[cfg(all(any(feature = "phy-raw_socket", feature = "phy-tap_interface"), unix))]
|
||||
#[cfg(all(any(feature = "phy-raw_socket", feature = "phy-tuntap_interface"), unix))]
|
||||
mod sys;
|
||||
|
||||
mod tracer;
|
||||
|
@ -100,10 +100,10 @@ mod pcap_writer;
|
|||
mod loopback;
|
||||
#[cfg(all(feature = "phy-raw_socket", unix))]
|
||||
mod raw_socket;
|
||||
#[cfg(all(feature = "phy-tap_interface", any(target_os = "linux", target_os = "android")))]
|
||||
mod tap_interface;
|
||||
#[cfg(all(feature = "phy-tuntap_interface", any(target_os = "linux", target_os = "android")))]
|
||||
mod tuntap_interface;
|
||||
|
||||
#[cfg(all(any(feature = "phy-raw_socket", feature = "phy-tap_interface"), unix))]
|
||||
#[cfg(all(any(feature = "phy-raw_socket", feature = "phy-tuntap_interface"), unix))]
|
||||
pub use self::sys::wait;
|
||||
|
||||
pub use self::tracer::Tracer;
|
||||
|
@ -114,8 +114,9 @@ pub use self::pcap_writer::{PcapLinkType, PcapMode, PcapSink, PcapWriter};
|
|||
pub use self::loopback::Loopback;
|
||||
#[cfg(all(feature = "phy-raw_socket", unix))]
|
||||
pub use self::raw_socket::RawSocket;
|
||||
#[cfg(all(feature = "phy-tap_interface", any(target_os = "linux", target_os = "android")))]
|
||||
pub use self::tap_interface::TapInterface;
|
||||
#[cfg(all(feature = "phy-tuntap_interface", any(target_os = "linux", target_os = "android")))]
|
||||
pub use self::tuntap_interface::TunTapInterface;
|
||||
|
||||
|
||||
#[cfg(feature = "medium-ethernet")]
|
||||
/// A tracer device for Ethernet frames.
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
#[cfg(any(feature = "phy-raw_socket",
|
||||
feature = "phy-tap_interface"))]
|
||||
#![allow(unused)]
|
||||
|
||||
pub const SIOCGIFMTU: libc::c_ulong = 0x8921;
|
||||
#[cfg(any(feature = "phy-raw_socket"))]
|
||||
pub const SIOCGIFINDEX: libc::c_ulong = 0x8933;
|
||||
#[cfg(any(feature = "phy-raw_socket"))]
|
||||
pub const ETH_P_ALL: libc::c_short = 0x0003;
|
||||
|
||||
#[cfg(feature = "phy-tap_interface")]
|
||||
pub const TUNSETIFF: libc::c_ulong = 0x400454CA;
|
||||
#[cfg(feature = "phy-tap_interface")]
|
||||
pub const IFF_TUN: libc::c_int = 0x0001;
|
||||
pub const IFF_TAP: libc::c_int = 0x0002;
|
||||
#[cfg(feature = "phy-tap_interface")]
|
||||
pub const IFF_NO_PI: libc::c_int = 0x1000;
|
||||
|
|
|
@ -12,15 +12,15 @@ mod imp;
|
|||
pub mod raw_socket;
|
||||
#[cfg(all(feature = "phy-raw_socket", not(any(target_os = "linux", target_os = "android")), unix))]
|
||||
pub mod bpf;
|
||||
#[cfg(all(feature = "phy-tap_interface", any(target_os = "linux", target_os = "android")))]
|
||||
pub mod tap_interface;
|
||||
#[cfg(all(feature = "phy-tuntap_interface", any(target_os = "linux", target_os = "android")))]
|
||||
pub mod tuntap_interface;
|
||||
|
||||
#[cfg(all(feature = "phy-raw_socket", any(target_os = "linux", target_os = "android")))]
|
||||
pub use self::raw_socket::RawSocketDesc;
|
||||
#[cfg(all(feature = "phy-raw_socket", not(any(target_os = "linux", target_os = "android")), unix))]
|
||||
pub use self::bpf::BpfDevice as RawSocketDesc;
|
||||
#[cfg(all(feature = "phy-tap_interface", any(target_os = "linux", target_os = "android")))]
|
||||
pub use self::tap_interface::TapInterfaceDesc;
|
||||
#[cfg(all(feature = "phy-tuntap_interface", any(target_os = "linux", target_os = "android")))]
|
||||
pub use self::tuntap_interface::TunTapInterfaceDesc;
|
||||
|
||||
/// Wait until given file descriptor becomes readable, but no longer than given timeout.
|
||||
pub fn wait(fd: RawFd, duration: Option<Duration>) -> io::Result<()> {
|
||||
|
@ -60,7 +60,7 @@ pub fn wait(fd: RawFd, duration: Option<Duration>) -> io::Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(all(any(feature = "phy-tap_interface", feature = "phy-raw_socket"), unix))]
|
||||
#[cfg(all(any(feature = "phy-tuntap_interface", feature = "phy-raw_socket"), unix))]
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
struct ifreq {
|
||||
|
@ -68,7 +68,7 @@ struct ifreq {
|
|||
ifr_data: libc::c_int /* ifr_ifindex or ifr_mtu */
|
||||
}
|
||||
|
||||
#[cfg(all(any(feature = "phy-tap_interface", feature = "phy-raw_socket"), unix))]
|
||||
#[cfg(all(any(feature = "phy-tuntap_interface", feature = "phy-raw_socket"), unix))]
|
||||
fn ifreq_for(name: &str) -> ifreq {
|
||||
let mut ifreq = ifreq {
|
||||
ifr_name: [0; libc::IF_NAMESIZE],
|
||||
|
@ -81,7 +81,7 @@ fn ifreq_for(name: &str) -> ifreq {
|
|||
}
|
||||
|
||||
#[cfg(all(any(target_os = "linux", target_os = "android"),
|
||||
any(feature = "phy-tap_interface", feature = "phy-raw_socket")))]
|
||||
any(feature = "phy-tuntap_interface", feature = "phy-raw_socket")))]
|
||||
fn ifreq_ioctl(lower: libc::c_int, ifreq: &mut ifreq,
|
||||
cmd: libc::c_ulong) -> io::Result<libc::c_int> {
|
||||
unsafe {
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
use std::io;
|
||||
use std::os::unix::io::{RawFd, AsRawFd};
|
||||
use super::*;
|
||||
use crate::wire::EthernetFrame;
|
||||
use crate::{phy::Medium, wire::EthernetFrame};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TapInterfaceDesc {
|
||||
pub struct TunTapInterfaceDesc {
|
||||
lower: libc::c_int,
|
||||
ifreq: ifreq
|
||||
ifreq: ifreq,
|
||||
medium: Medium,
|
||||
}
|
||||
|
||||
impl AsRawFd for TapInterfaceDesc {
|
||||
impl AsRawFd for TunTapInterfaceDesc {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.lower
|
||||
}
|
||||
}
|
||||
|
||||
impl TapInterfaceDesc {
|
||||
pub fn new(name: &str) -> io::Result<TapInterfaceDesc> {
|
||||
impl TunTapInterfaceDesc {
|
||||
pub fn new(name: &str, medium: Medium) -> io::Result<TunTapInterfaceDesc> {
|
||||
let lower = unsafe {
|
||||
let lower = libc::open("/dev/net/tun\0".as_ptr() as *const libc::c_char,
|
||||
libc::O_RDWR | libc::O_NONBLOCK);
|
||||
|
@ -24,14 +25,21 @@ impl TapInterfaceDesc {
|
|||
lower
|
||||
};
|
||||
|
||||
Ok(TapInterfaceDesc {
|
||||
lower: lower,
|
||||
ifreq: ifreq_for(name)
|
||||
Ok(TunTapInterfaceDesc {
|
||||
lower,
|
||||
ifreq: ifreq_for(name),
|
||||
medium,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn attach_interface(&mut self) -> io::Result<()> {
|
||||
self.ifreq.ifr_data = imp::IFF_TAP | imp::IFF_NO_PI;
|
||||
let mode = match self.medium {
|
||||
#[cfg(feature = "medium-ip")]
|
||||
Medium::Ip => imp::IFF_TUN,
|
||||
#[cfg(feature = "medium-ethernet")]
|
||||
Medium::Ethernet => imp::IFF_TAP,
|
||||
};
|
||||
self.ifreq.ifr_data = mode | imp::IFF_NO_PI;
|
||||
ifreq_ioctl(self.lower, &mut self.ifreq, imp::TUNSETIFF).map(|_| ())
|
||||
}
|
||||
|
||||
|
@ -46,9 +54,19 @@ impl TapInterfaceDesc {
|
|||
|
||||
unsafe { libc::close(lower); }
|
||||
|
||||
// Propagate error after close, to ensure we always close.
|
||||
let ip_mtu = ip_mtu?;
|
||||
|
||||
// SIOCGIFMTU returns the IP MTU (typically 1500 bytes.)
|
||||
// smoltcp counts the entire Ethernet packet in the MTU, so add the Ethernet header size to it.
|
||||
Ok(ip_mtu? + EthernetFrame::<&[u8]>::header_len())
|
||||
let mtu = match self.medium {
|
||||
#[cfg(feature = "medium-ip")]
|
||||
Medium::Ip => ip_mtu,
|
||||
#[cfg(feature = "medium-ethernet")]
|
||||
Medium::Ethernet => ip_mtu + EthernetFrame::<&[u8]>::header_len(),
|
||||
};
|
||||
|
||||
Ok(mtu)
|
||||
}
|
||||
|
||||
pub fn recv(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
|
||||
|
@ -70,7 +88,7 @@ impl TapInterfaceDesc {
|
|||
}
|
||||
}
|
||||
|
||||
impl Drop for TapInterfaceDesc {
|
||||
impl Drop for TunTapInterfaceDesc {
|
||||
fn drop(&mut self) {
|
||||
unsafe { libc::close(self.lower); }
|
||||
}
|
|
@ -8,44 +8,46 @@ use crate::Result;
|
|||
use crate::phy::{self, sys, DeviceCapabilities, Device, Medium};
|
||||
use crate::time::Instant;
|
||||
|
||||
/// A virtual Ethernet interface.
|
||||
/// A virtual TUN (IP) or TAP (Ethernet) interface.
|
||||
#[derive(Debug)]
|
||||
pub struct TapInterface {
|
||||
lower: Rc<RefCell<sys::TapInterfaceDesc>>,
|
||||
mtu: usize
|
||||
pub struct TunTapInterface {
|
||||
lower: Rc<RefCell<sys::TunTapInterfaceDesc>>,
|
||||
mtu: usize,
|
||||
medium: Medium,
|
||||
}
|
||||
|
||||
impl AsRawFd for TapInterface {
|
||||
impl AsRawFd for TunTapInterface {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.lower.borrow().as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl TapInterface {
|
||||
/// Attaches to a TAP interface called `name`, or creates it if it does not exist.
|
||||
impl TunTapInterface {
|
||||
/// Attaches to a TUN/TAP interface called `name`, or creates it if it does not exist.
|
||||
///
|
||||
/// If `name` is a persistent interface configured with UID of the current user,
|
||||
/// no special privileges are needed. Otherwise, this requires superuser privileges
|
||||
/// or a corresponding capability set on the executable.
|
||||
pub fn new(name: &str) -> io::Result<TapInterface> {
|
||||
let mut lower = sys::TapInterfaceDesc::new(name)?;
|
||||
pub fn new(name: &str, medium: Medium) -> io::Result<TunTapInterface> {
|
||||
let mut lower = sys::TunTapInterfaceDesc::new(name, medium)?;
|
||||
lower.attach_interface()?;
|
||||
let mtu = lower.interface_mtu()?;
|
||||
Ok(TapInterface {
|
||||
Ok(TunTapInterface {
|
||||
lower: Rc::new(RefCell::new(lower)),
|
||||
mtu: mtu
|
||||
mtu,
|
||||
medium,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Device<'a> for TapInterface {
|
||||
impl<'a> Device<'a> for TunTapInterface {
|
||||
type RxToken = RxToken;
|
||||
type TxToken = TxToken;
|
||||
|
||||
fn capabilities(&self) -> DeviceCapabilities {
|
||||
DeviceCapabilities {
|
||||
max_transmission_unit: self.mtu,
|
||||
medium: Medium::Ethernet,
|
||||
medium: self.medium,
|
||||
..DeviceCapabilities::default()
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +91,7 @@ impl phy::RxToken for RxToken {
|
|||
|
||||
#[doc(hidden)]
|
||||
pub struct TxToken {
|
||||
lower: Rc<RefCell<sys::TapInterfaceDesc>>,
|
||||
lower: Rc<RefCell<sys::TunTapInterfaceDesc>>,
|
||||
}
|
||||
|
||||
impl phy::TxToken for TxToken {
|
Loading…
Reference in New Issue