Skip to content
Open
20 changes: 20 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: CI

on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Setup test interface
run: sudo sh tests/setup.sh
- name: Build
run: cargo build --all-targets
- name: Test
run: cargo test
- name: Clippy
run: cargo clippy --all-targets -- -D warnings
- name: Doc
run: cargo doc --no-deps
28 changes: 0 additions & 28 deletions .travis.yml

This file was deleted.

33 changes: 33 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,36 @@
# 0.2.0

## Breaking Changes

* Async API completely rewritten: `Stream + Sink` (tokio-core 0.1 / futures 0.1) replaced with
`AsyncRead + AsyncWrite` (tokio 1.x / `AsyncFd`). The `Async` struct no longer implements
`Stream` or `Sink`; use `AsyncReadExt` / `AsyncWriteExt` methods instead.
* Feature renamed: `tokio` → `async`. Enable with `--features async` (on by default).

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think renaming to async is entirely correct - this does depend on a specific async runtime, tokio.

Also, I don't think it makes sense to list documentation to Rust, namely how to enable features - and besides, nobody really does it by that flag, they do so through their Cargo.toml.

* `set_recv_bufsize` removed from `Async`; external buffer sizing is now caller-managed
via `AsyncRead`.

## Dependency Upgrades

* `tokio-core` 0.1 → `tokio` 1.x (features: net, rt, rt-multi-thread, io-util, macros, time)
* `futures` 0.1 → removed (tokio provides async traits)
* `mio` 0.6 → removed (tokio's `AsyncFd` replaces raw mio)
* `etherparse` 0.9 → 0.17 (dev-dependency)
* `serial_test` 0.4 → 3.x (dev-dependency)
* `version-sync` → removed

## Code Modernization

* Edition 2024 compliance: `extern "C"` → `unsafe extern "C"`, removed `extern crate` declarations
* `build.rs`: removed `extern crate cc;`
* `[badges]` section removed from `Cargo.toml` (deprecated by crates.io)
* Travis CI replaced with GitHub Actions (`.github/workflows/ci.yml`)
* `tests/version.rs` removed (depended on dropped `version-sync`)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are somewhat internal things. I don't think these belong to changelog - that's for consumers of the crate.


## Upstream Fixes (since 0.1.4)

* Fixed `cmd` function in examples to accept arbitrary command instead of hardcoded `"ip"` (#17)
* Fixed typo in doc comment (#16)

# 0.1.4

* Ability to set nonblocking without tokio (#12).
Expand Down
30 changes: 12 additions & 18 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "tun-tap"
# Also don't forget to update the version in the html_root_url attribute in src/lib.rs
version = "0.1.4"
edition = "2024"
version = "0.2.0"
authors = ["Michal 'vorner' Vaner <vorner@vorner.cz>"]
description = "TUN/TAP interface wrapper"
documentation = "https://docs.rs/tun-tap"
Expand All @@ -11,24 +11,18 @@ keywords = ["tun", "tap", "network"]
categories = ["network-programming"]
license = "Apache-2.0/MIT"

[badges]
travis-ci = { repository = "vorner/tuntap" }
maintenance = { status = "passively-maintained" }

[features]
default = ["tokio"]
tokio = ["futures", "libc", "mio", "tokio-core"]

[build-dependencies]
cc = "~1"
default = ["async"]
async = ["dep:tokio", "dep:libc", "libc"]
libc = ["dep:libc"]

[dependencies]
futures = { version = "~0.1", optional = true }
libc = { version = "~0.2", optional = true }
mio = { version = "~0.6", optional = true }
tokio-core = { version = "~0.1", optional = true }
libc = { version = "0.2", optional = true }
tokio = { version = "1", features = ["net", "rt", "rt-multi-thread", "io-util", "macros", "time"], optional = true }

[build-dependencies]
cc = "1"

[dev-dependencies]
version-sync = "~0.9"
etherparse = "~0.9"
serial_test = "~0.4"
etherparse = "0.17"
serial_test = "3"
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# TunTap

[![Travis Build Status](https://api.travis-ci.org/vorner/tuntap.png?branch=master)](https://travis-ci.org/vorner/tuntap)
[![CI](https://github.com/vorner/tuntap/actions/workflows/ci.yml/badge.svg)](https://github.com/vorner/tuntap/actions/workflows/ci.yml)

TUN/TAP wrapper for Rust.

Expand Down
2 changes: 0 additions & 2 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
extern crate cc;

use cc::Build;

fn main() {
Expand Down
7 changes: 4 additions & 3 deletions examples/dump_iface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
//! raw data of the packets that arrive.
//!
//! You really do want better error handling than all these unwraps.
extern crate tun_tap;

use std::process::Command;

Expand All @@ -28,8 +27,10 @@ fn main() {
// Configure the „local“ (kernel) endpoint.
cmd("ip", &["addr", "add", "dev", iface.name(), "10.107.1.2/24"]);
cmd("ip", &["link", "set", "up", "dev", iface.name()]);
println!("Created interface {}. Send some packets into it and see they're printed here",
iface.name());
println!(
"Created interface {}. Send some packets into it and see they're printed here",
iface.name()
);
println!("You can for example ping 10.107.1.3 (it won't answer)");
// That 1500 is a guess for the IFace's MTU (we probably could configure it explicitly). 4 more
// for TUN's „header“.
Expand Down
21 changes: 9 additions & 12 deletions examples/pingpong.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
//! The `dump_iface` example is simpler (contains only the reading end), so you want to start with
//! that.
//!
//! You really do want better error handling than all these unwraps.

extern crate tun_tap;
//! that.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated.


use std::process::Command;
use std::sync::Arc;
Expand All @@ -19,10 +17,12 @@ use tun_tap::{Iface, Mode};

/// The packet data. Note that it is prefixed by 4 bytes ‒ two bytes are flags, another two are
/// protocol. 8, 0 is IPv4, 134, 221 is IPv6. <https://en.wikipedia.org/wiki/EtherType#Examples>.
const PING: &[u8] = &[0, 0, 8, 0, 69, 0, 0, 84, 44, 166, 64, 0, 64, 1, 247, 40, 10, 107, 1, 2, 10,
107, 1, 3, 8, 0, 62, 248, 19, 160, 0, 2, 232, 228, 34, 90, 0, 0, 0, 0, 216, 83, 3, 0, 0, 0, 0,
0, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55];
const PING: &[u8] = &[
0, 0, 8, 0, 69, 0, 0, 84, 44, 166, 64, 0, 64, 1, 247, 40, 10, 107, 1, 2, 10, 107, 1, 3, 8, 0,
62, 248, 19, 160, 0, 2, 232, 228, 34, 90, 0, 0, 0, 0, 216, 83, 3, 0, 0, 0, 0, 0, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
];

/// Run a shell command. Panic if it fails in any way.
fn cmd(cmd: &str, args: &[&str]) {
Expand Down Expand Up @@ -55,7 +55,7 @@ fn main() {
assert!(amount == PING.len());
}
});
let reader = thread::spawn(move || {
thread::spawn(move || {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason you're no longer waiting for the reader - and more importantly, dropping any panics it might have produced.

// MTU + TUN header
let mut buffer = vec![0; 1504];
loop {
Expand All @@ -65,8 +65,5 @@ fn main() {
println!("Packet: {:?}", &buffer[4..size]);
}
});
writer.join()
.unwrap();
reader.join()
.unwrap();
writer.join().unwrap();
}
57 changes: 29 additions & 28 deletions examples/tokio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,27 @@
//! This creates an interface, configures the kernel endpoint and sends pings to that endpoint. It
//! prints whatever packets come back (which should include the pong responses).
//!
//! This does essentialy the same as the `pingpoing` example. However, instead of threads, this
//! This does essentially the same as the `pingpong` example. However, instead of threads, this
//! uses tokio asynchronous event loop to multiplex between the two directions.
//!
//! You really do want better error handling than all these unwraps.

extern crate futures;
extern crate tokio_core;
extern crate tun_tap;

use std::process::Command;
use std::time::Duration;

use futures::{Future, Stream};
use tokio_core::reactor::{Core, Interval};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::time;
use tun_tap::r#async::Async;
use tun_tap::{Iface, Mode};
use tun_tap::async::Async;

/// The packet data. Note that it is prefixed by 4 bytes two bytes are flags, another two are
/// The packet data. Note that it is prefixed by 4 bytes two bytes are flags, another two are
/// protocol. 8, 0 is IPv4, 134, 221 is IPv6. <https://en.wikipedia.org/wiki/EtherType#Examples>.
const PING: &[u8] = &[0, 0, 8, 0, 69, 0, 0, 84, 44, 166, 64, 0, 64, 1, 247, 40, 10, 107, 1, 2, 10,
107, 1, 3, 8, 0, 62, 248, 19, 160, 0, 2, 232, 228, 34, 90, 0, 0, 0, 0, 216, 83, 3, 0, 0, 0, 0,
0, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55];
const PING: &[u8] = &[
0, 0, 8, 0, 69, 0, 0, 84, 44, 166, 64, 0, 64, 1, 247, 40, 10, 107, 1, 2, 10, 107, 1, 3, 8, 0,
62, 248, 19, 160, 0, 2, 232, 228, 34, 90, 0, 0, 0, 0, 216, 83, 3, 0, 0, 0, 0, 0, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
];

/// Run a shell command. Panic if it fails in any way.
fn cmd(cmd: &str, args: &[&str]) {
Expand All @@ -38,26 +36,29 @@ fn cmd(cmd: &str, args: &[&str]) {
assert!(ecode.success(), "Failed to execte {}", cmd);
}

fn main() {
#[tokio::main]
async fn main() {
let iface = Iface::new("testtun%d", Mode::Tun).unwrap();
eprintln!("Iface: {:?}", iface);
// Configure the local (kernel) endpoint. Kernel is (the host) 10.107.1.3, we (the app)
// Configure the "local" (kernel) endpoint. Kernel is (the host) 10.107.1.3, we (the app)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On one hand, you're replacing dashes with the more correct long ones, on the other, you're removing the typographically correct quotes?

// pretend to be 10.107.1.2.
cmd("ip", &["addr", "add", "dev", iface.name(), "10.107.1.3/24"]);
cmd("ip", &["link", "set", "up", "dev", iface.name()]);
let mut core = Core::new().unwrap();
let iface = Async::new(iface, &core.handle()).unwrap();
let (sink, stream) = iface.split();
let writer = Interval::new(Duration::from_secs(1), &core.handle())
.unwrap()
.map(|_| {
let (mut reader, mut writer) = tokio::io::split(Async::new(iface).unwrap());
let write_task = tokio::spawn(async move {
let mut interval = time::interval(Duration::from_secs(1));
loop {
interval.tick().await;
println!("Sending ping");
PING.to_owned()
})
.forward(sink);
let reader = stream.for_each(|packet| {
println!("Received: {:?}", packet);
Ok(())
writer.write_all(PING).await.unwrap();
}
});
let read_task = tokio::spawn(async move {
let mut buf = vec![0u8; 1504];
loop {
let n = reader.read(&mut buf).await.unwrap();
println!("Received: {:?}", &buf[..n]);
}
});
core.run(reader.join(writer)).unwrap();
tokio::try_join!(write_task, read_task).unwrap();

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the motivation behind making it run forever instead of just once? The PR seems to be about modernizing things, but you seem to be doing a lot more for unexplained reasons.

}
Loading