Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace maybenot submodule with direct ffi re-export wrapper crate #22

Open
wants to merge 2 commits into
base: mullvad
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions MULLVAD-CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 ./...
Expand Down
2 changes: 1 addition & 1 deletion device/daita.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

// #include <stdio.h>
// #include <stdlib.h>
// #include "../maybenot/crates/maybenot-ffi/maybenot.h"
// #include "../maybenot-ffi/maybenot.h"
// #cgo LDFLAGS: -L${SRCDIR}/../ -lmaybenot -lm
import "C"

Expand Down
1 change: 0 additions & 1 deletion maybenot
Submodule maybenot deleted from d40056
16 changes: 16 additions & 0 deletions maybenot-ffi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
39 changes: 39 additions & 0 deletions maybenot-ffi/Makefile
Original file line number Diff line number Diff line change
@@ -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)
22 changes: 22 additions & 0 deletions maybenot-ffi/README.md
Original file line number Diff line number Diff line change
@@ -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'
```
229 changes: 229 additions & 0 deletions maybenot-ffi/maybenot.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
/* Generated with cbindgen:0.27.0 */

/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

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);
1 change: 1 addition & 0 deletions maybenot-ffi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub use maybenot_ffi::*;