diff --git a/MULLVAD-CHANGELOG.md b/MULLVAD-CHANGELOG.md index 7ede40d..516bb6e 100644 --- a/MULLVAD-CHANGELOG.md +++ b/MULLVAD-CHANGELOG.md @@ -20,6 +20,8 @@ Line wrap the file at 100 chars. Th * **Security**: in case of vulnerabilities. ## [Unreleased] +### Changed +- Change how maybenot-ffi is included and built as a dependency to wireguard-go with DAITA support. ## [0.1.5] - 2024-12-12 diff --git a/Makefile b/Makefile index 3e0fbfd..fe9a7c2 100644 --- a/Makefile +++ b/Makefile @@ -27,8 +27,8 @@ install: wireguard-go daita: libmaybenot.a go build --tags daita -v -o wireguard-go -libmaybenot.a: $(wildcard maybenot/*) - make --directory maybenot/crates/maybenot-ffi/ DESTINATION=$(LIBDEST) TARGET=$(TARGET) +libmaybenot.a: $(wildcard maybenot-ffi/*) + make --directory maybenot-ffi DESTINATION=$(LIBDEST) TARGET=$(TARGET) test: go test ./... diff --git a/device/daita.go b/device/daita.go index fbc42b5..fa5999b 100644 --- a/device/daita.go +++ b/device/daita.go @@ -12,7 +12,7 @@ import ( // #include // #include -// #include "../maybenot/crates/maybenot-ffi/maybenot.h" +// #include "../maybenot-ffi/maybenot.h" // #cgo LDFLAGS: -L${SRCDIR}/../ -lmaybenot -lm import "C" diff --git a/maybenot b/maybenot deleted file mode 160000 index d40056a..0000000 --- a/maybenot +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d40056adfa854d86e1d515d56e9a703090e2473c diff --git a/maybenot-ffi/Cargo.toml b/maybenot-ffi/Cargo.toml new file mode 100644 index 0000000..e2ed373 --- /dev/null +++ b/maybenot-ffi/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "maybenot-ffi" +license = "MIT OR Apache-2.0" +edition = "2021" + +# We are not setting crate-type = ["staticlib"] here, because +# we solve that by passing --crate-type=staticlib in the accompanying +# Makefile instead. We do this because we only want to build it as a +# staticlib on some platforms. On the other platforms it's included +# as a normal dependency. + +[dependencies] +# This should be the one single place where we actually specify the +# maybenot-ffi dependency and its version. +# If this is bumped, check if `maybenot.h` has to be updated. See README.md +maybenot-ffi = "2.0.1" diff --git a/maybenot-ffi/Makefile b/maybenot-ffi/Makefile new file mode 100644 index 0000000..b7e8b40 --- /dev/null +++ b/maybenot-ffi/Makefile @@ -0,0 +1,39 @@ +CARGO ?= cargo +TARGET ?= +PROFILE ?= release +DESTINATION ?= . + +CARGO_OUTPUT_DIR := $(CARGO_TARGET_DIR)/$(TARGET)/$(PROFILE) +CARGOFLAGS += --target-dir $(CARGO_TARGET_DIR) + +ifeq ($(PROFILE), release) + CARGOFLAGS += --release --locked +endif + +ifneq ($(TARGET),) + CARGOFLAGS += --target + CARGOFLAGS += $(TARGET) +endif + +.PHONY: clean check-env + + +# copy the library to the final destination, and strip the _ffi part +$(DESTINATION)/libmaybenot.a: $(CARGO_OUTPUT_DIR)/libmaybenot_ffi.a check-env +# Copy first prerequisite ($^) to the target ($@) + cp $< $@ + +# build maybenot-ffi as a static library +$(CARGO_OUTPUT_DIR)/libmaybenot_ffi.a: src/*.rs Cargo.toml check-env + RUSTFLAGS="-C metadata=maybenot-ffi" ${CARGO} rustc --crate-type=staticlib $(CARGOFLAGS) + + +# Verify that required environment variables are set. +check-env: +ifndef CARGO_TARGET_DIR + $(error CARGO_TARGET_DIR is undefined) +endif + +clean: + rm -f $(DESTINATION)/libmaybenot.a + ${CARGO} clean $(CARGOFLAGS) diff --git a/maybenot-ffi/README.md b/maybenot-ffi/README.md new file mode 100644 index 0000000..32d3f78 --- /dev/null +++ b/maybenot-ffi/README.md @@ -0,0 +1,22 @@ +This is just an empty wrapper around the real `maybenot-ffi` crate. It just depends +on maybenot-ffi and re-exports the entire API. It also contains the C header +file, and a Makefile to aid building a static library out of it. + +This allows us to include maybenot-ffi in a workspace without it being a direct or +transitive Rust dependency in the workspace. This is achieved by including this crate in the +workspace as a member. Doing this allows tracking the checksums and versions of `maybenot-ffi` +and its dependencies in the workspace lockfile, for simpler version management, +supply chain security and easier reproducible builds. + +# maybenot.h + +The C header file is copied here from the real `maybenot-ffi` crate. + +To update the header, just copy it from the corresponding `maybenot-ffi` release (the same version +as the one specified in [`Cargo.toml`](./Cargo.toml)). +You can use this command, just replace `${VERSION}` with the version you want the header from. +(You first need to install `cargo download` subcommand with `cargo install cargo-download`): +```bash +cargo download maybenot-ffi==${VERSION} | \ + tar xzvf - --wildcards --strip-components=1 '*/maybenot.h' +``` diff --git a/maybenot-ffi/maybenot.h b/maybenot-ffi/maybenot.h new file mode 100644 index 0000000..f7f99b8 --- /dev/null +++ b/maybenot-ffi/maybenot.h @@ -0,0 +1,229 @@ +/* Generated with cbindgen:0.27.0 */ + +/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */ + +#include +#include +#include +#include + +enum MaybenotEventType { + MaybenotEventType_NormalRecv = 0, + MaybenotEventType_PaddingRecv = 1, + MaybenotEventType_TunnelRecv = 2, + MaybenotEventType_NormalSent = 3, + MaybenotEventType_PaddingSent = 4, + MaybenotEventType_TunnelSent = 5, + MaybenotEventType_BlockingBegin = 6, + MaybenotEventType_BlockingEnd = 7, + MaybenotEventType_TimerBegin = 8, + MaybenotEventType_TimerEnd = 9, +}; +typedef uint32_t MaybenotEventType; + +/** + * An FFI friendly result error code type. + */ +enum MaybenotResult { + /** + * Operation completed successfully + */ + MaybenotResult_Ok = 0, + /** + * The machine string wasn't valid UTF-8 + */ + MaybenotResult_MachineStringNotUtf8 = 1, + /** + * Failed to parse machine string + */ + MaybenotResult_InvalidMachineString = 2, + /** + * Failed to start framework + */ + MaybenotResult_StartFramework = 3, + /** + * A null pointer was encountered + */ + MaybenotResult_NullPointer = 4, +}; +typedef uint32_t MaybenotResult; + +/** + * The different types of timers used by a [Machine]. + */ +enum MaybenotTimer { + /** + * The scheduled timer for actions with a timeout. + */ + MaybenotTimer_Action = 0, + /** + * The machine's internal timer, updated by the machine using [MaybenotAction::UpdateTimer]. + */ + MaybenotTimer_Internal = 1, + /** + * Apply to all timers. + */ + MaybenotTimer_All = 2, +}; +typedef uint32_t MaybenotTimer; + +/** + * A running Maybenot instance. + * + * - Create it: [maybenot_start]. + * - Feed it actions: [maybenot_on_events]. + * - Stop it: [maybenot_stop]. + */ +typedef struct MaybenotFramework MaybenotFramework; + +typedef struct MaybenotEvent { + MaybenotEventType event_type; + /** + * The ID of the machine that triggered the event, if any. + */ + uintptr_t machine; +} MaybenotEvent; + +typedef struct MaybenotDuration { + /** + * Number of whole seconds + */ + uint64_t secs; + /** + * A nanosecond fraction of a second. + */ + uint32_t nanos; +} MaybenotDuration; + +/** + * The action to be taken by the framework user. + */ +enum MaybenotAction_Tag { + /** + * Cancel the timer for a machine. + */ + MaybenotAction_Cancel = 0, + /** + * Schedule padding to be injected after the given timeout for a machine. + */ + MaybenotAction_SendPadding = 1, + /** + * Schedule blocking of outgoing traffic after the given timeout for a machine. + */ + MaybenotAction_BlockOutgoing = 2, + /** + * Update the timer duration for a machine. + */ + MaybenotAction_UpdateTimer = 3, +}; +typedef uint32_t MaybenotAction_Tag; + +typedef struct MaybenotAction_Cancel_Body { + /** + * The machine that generated the action. + */ + uintptr_t machine; + MaybenotTimer timer; +} MaybenotAction_Cancel_Body; + +typedef struct MaybenotAction_SendPadding_Body { + /** + * The machine that generated the action. + */ + uintptr_t machine; + /** + * The time to wait before injecting a padding packet. + */ + struct MaybenotDuration timeout; + bool replace; + bool bypass; +} MaybenotAction_SendPadding_Body; + +typedef struct MaybenotAction_BlockOutgoing_Body { + /** + * The machine that generated the action. + */ + uintptr_t machine; + /** + * The time to wait before blocking. + */ + struct MaybenotDuration timeout; + bool replace; + bool bypass; + /** + * How long to block. + */ + struct MaybenotDuration duration; +} MaybenotAction_BlockOutgoing_Body; + +typedef struct MaybenotAction_UpdateTimer_Body { + uintptr_t machine; + struct MaybenotDuration duration; + bool replace; +} MaybenotAction_UpdateTimer_Body; + +typedef struct MaybenotAction { + MaybenotAction_Tag tag; + union { + MaybenotAction_Cancel_Body cancel; + MaybenotAction_SendPadding_Body send_padding; + MaybenotAction_BlockOutgoing_Body block_outgoing; + MaybenotAction_UpdateTimer_Body update_timer; + }; +} MaybenotAction; + +/** + * Get the version of maybenot-ffi as a null terminated UTF-8-string. + * + * Example: `maybenot-ffi/1.0.1` + */ +const char *maybenot_version(void); + +/** + * Start a new [`MaybenotFramework`] instance. + * + * # Safety + * - `machines_str` must be a null-terminated UTF-8 string, containing LF-separated machines. + * - `out` must be a valid pointer to some valid and aligned pointer-sized memory. + * - The pointer written to `out` is NOT safe to be used concurrently. + */ +MaybenotResult maybenot_start(const char *machines_str, + double max_padding_frac, + double max_blocking_frac, + struct MaybenotFramework **out); + +/** + * Get the number of machines running in the [`MaybenotFramework`] instance. + * + * # Safety + * - `this` must have been created by [`maybenot_start`]. + */ +uintptr_t maybenot_num_machines(struct MaybenotFramework *this_); + +/** + * Stop a running [`MaybenotFramework`] instance. This will free the maybenot pointer. + * + * # Safety + * - `this` MUST have been created by [`maybenot_start`]. + * - `this` MUST NOT be used after it has been passed to [`maybenot_stop`]. + */ +void maybenot_stop(struct MaybenotFramework *this_); + +/** + * Feed events to the [`MaybenotFramework`] instance. + * + * This may generate [super::MaybenotAction]s that will be written to `actions_out`. + * The number of actions will be written to `num_actions_out`. + * + * # Safety + * - `this` MUST have been created by [`maybenot_start`]. + * - `events` MUST be a valid pointer to an array of size `num_events`. + * - `actions_out` MUST have capacity for [`maybenot_num_machines`] items of size + * `sizeof(MaybenotAction)` bytes. + * - `num_actions_out` MUST be a valid pointer where a 64bit int can be written. + */ +MaybenotResult maybenot_on_events(struct MaybenotFramework *this_, + const struct MaybenotEvent *events, + uintptr_t num_events, + struct MaybenotAction *actions_out, + uintptr_t *num_actions_out); diff --git a/maybenot-ffi/src/lib.rs b/maybenot-ffi/src/lib.rs new file mode 100644 index 0000000..2e6612f --- /dev/null +++ b/maybenot-ffi/src/lib.rs @@ -0,0 +1 @@ +pub use maybenot_ffi::*;