Installing Marionnet

Which method to choose, what each one installs, and what is left to do afterwards. For the commands alone, without the explanations: INSTALL-quick-guide.md.

What this page is for

Marionnet is published in three ready-to-use forms: an apt repository, a dnf/zypper repository and a precompiled archive. All three come from the same publication directory, on www.marionnet.org, and contain the same program. The choice therefore depends only on the package manager of your machine.

Whatever the method, two steps follow: fetching the images and the kernels (§ 2), then granting the sudoers rule (§ 3). This page also explains why each precaution exists, and what to do when something does not work (§ 6).

Image
the disk of a virtual machine: Debian trixie, Debian wheezy, or guignol, the small image that also serves as a router.
UML kernel
the Linux kernel that runs a Marionnet virtual machine as an ordinary program of your machine. There are two of them: linux-6.12.95 (64-bit) and linux-6.12.95-i386 (32-bit).
Precompiled archive
the application, already compiled, in a .tar.xz file (a tarball), for the distributions that have no Marionnet repository.
Release
the set of files put online together: application, packages, images, kernels.
Sudoers rule
the permission that lets Marionnet create its network interfaces on your machine. It is made of three files in /etc/sudoers.d/, blocks (a), (b) and (c) of § 3.
Door
a small script, owned by root, that the sudoers rule allows instead of the ip or iptables commands. It checks its arguments before acting.

The installation at a glance

1. the application    § 1.A apt repository
        │             § 1.B dnf/zypper repository
        │             § 1.C precompiled archive
        │             § 1.D from source
        ▼
2. images, kernels    § 2 marionnet-get-images
        │
        ▼
3. sudoers rule       § 3 marionnet-sudoers.sh install
        │
        ▼
4. launch             § 4 marionnet

At step 1, the four methods are alternatives: only one concerns you. Steps 2, 3 and 4 then apply to all of them.

Without images or kernels, Marionnet starts, but it says so and cannot run any virtual machine. They weigh several gibibytes and change at their own pace: that is why they are fetched separately (§ 2).

Marionnet is a graphical program. It needs an X display (DISPLAY), and opens access to it for the virtual machines with xhost (§ 3.2).

On this page, a relative path starts from the directory of this file: doc-src/ in the source tree, <prefix>/share/doc/marionnet/ on a machine where Marionnet is installed.

Which systems this was tested on

Each line of the table was measured by test benches: scripts that install Marionnet in a bare container of the distribution, then ask the machine what it got. They are in the source repository, under Makefile.d/*.bench/ and bin/scripts/marionnet-install.sh.bench/.

System glibc archive (§ 1.C) apt (§ 1.A) dnf/zypper (§ 1.B)
Ubuntu 20.04 LTS (focal) 2.31 49 / 0 41 / 0 —
Ubuntu 22.04 LTS (jammy) 2.35 49 / 0 41 / 0 —
Ubuntu 24.04 LTS (noble) 2.39 49 / 0 41 / 0 —
Ubuntu 26.04 LTS 2.41 49 / 0 41 / 0 —
Debian 11 (bullseye) 2.31 49 / 0 41 / 0 —
Debian 12 (bookworm) 2.36 49 / 0 41 / 0 —
Debian 13 (trixie) 2.41 49 / 0 41 / 0 —
Rocky Linux 9 2.34 — — 60 / 0
AlmaLinux 9 2.34 — — 58 / 0
Rocky Linux 10 2.39 — — 61 / 0
AlmaLinux 10 2.39 — — 59 / 0
Fedora 42 2.41 — — 60 / 0
openSUSE Leap 15.6 2.38 — — 56 / 0
openSUSE Leap 16.0 2.40 — — 58 / 0

Each cell reads cases passed / cases failed. The installer marionnet-install.sh is measured separately, on the seven Debian and Ubuntu systems: 504 cases, no failure.

On the RHEL 10 family, the full score includes no router: there is none yet on this family (§ 1.B).

What the table means for your machine. Marionnet and its UML kernels are dynamically linked programs. They require a glibc at least as recent as that of the system they were compiled on, never the other way round. The release is therefore compiled on the oldest system served in each family: Debian 11 (glibc 2.31) for the Debian packages and the archive, Rocky Linux 9 (glibc 2.34) for the RPM packages. Every more recent distribution receives the same files, and you have no variant to choose.

The precompiled archive carries this minimum glibc in its file name (marionnet_<version>-r<rev>_<arch>_glibc<x.y>.tar.xz). marionnet-install.sh reads it there: on a machine that is too old, it refuses and says so, instead of installing a program that would not start. The packages say the same thing in the language of their package manager (libc6 (>= ...), libc.so.6(GLIBC_...)), and apt or dnf refuse them on their own.

openSUSE Leap 15.6. It is served only since the release of 2026-09-13. Before, Marionnet depended on the uml-utilities package, compiled by the project against readline 8, whereas Leap 15.x provides readline 7: zypper refused the package. The two programs that were needed from that package, the mconsole client and the UML kernel's port-helper, are now compiled with Marionnet, without readline, under the names marionnet_uml_mconsole and marionnet_uml_port_helper.

Older than the table. Ubuntu 18.04 and Debian 10 have a glibc that is too old and are not served. You can still compile Marionnet from source there (§ 1.D), provided their packages are enough.

1. Install the application: one method, your choice

Choose one of the four methods 1.A to 1.D, according to your machine; the others do not concern you. Sections 2, 3 and 4 then apply to every method.

Your machine Take §
Debian, Ubuntu and derivatives the apt repository § 1.A
Fedora, RHEL family (Rocky, AlmaLinux), openSUSE the dnf/zypper repository § 1.B
any other distribution, or no package manager wanted the precompiled archive § 1.C
you want to modify Marionnet the source § 1.D

Before any method, on a minimal Debian or Ubuntu

A minimal installation has neither certificates nor curl. Install them first, otherwise nothing can read the site.

The three methods read the site over https. But a minimal Debian or Ubuntu, a container image for instance, has no certificate store at all (measured on Debian 12 and 13, Ubuntu 24.04 and 26.04; the RPM images have one). Without it, apt does not read the repository and the installer does not read the list of published files, although the server answers.

sudo apt update && sudo apt install ca-certificates curl

curl is in the same command because a slim image has nothing to download with either, and § 1.A needs it to fetch the key (wget -O works just as well as curl -o).

marionnet-install.sh recognises this case and names it, rather than blaming the network. It cannot repair it by itself: that would take the very package manager that does not work yet.

1.A Debian and Ubuntu: the apt repository

Fetch the project's key and check its fingerprint, declare the repository, install marionnet. Measured on Debian 12 and 13, Ubuntu 24.04 and 26.04.

# 1. the key: fetched, looked at (see "The key"), and only then trusted
sudo install -d /etc/apt/keyrings
sudo curl -o /etc/apt/keyrings/marionnet.asc \
     https://git.launchpad.net/marionnet/plain/marionnet-archive-keyring.asc
sudo apt install gnupg
# must print the fingerprint below
gpg --show-keys /etc/apt/keyrings/marionnet.asc

# 2. the repository, then the application
echo 'deb [signed-by=/etc/apt/keyrings/marionnet.asc] https://www.marionnet.org/download/apt/ ./' \
  | sudo tee /etc/apt/sources.list.d/marionnet.list
sudo apt update
sudo apt install marionnet

The address download/apt always follows the current release series: you will not have to change this line when the series changes.

The key

The repository is signed, and signed-by= tells apt to check the signature with this key:

Marionnet Archive Signing Key <loddo@lipn.univ-paris13.fr>
4A65 3434 0BF9 7733 E74C  9DFC 12E4 6000 225F 0E56

It is fetched from git.launchpad.net, and not from www.marionnet.org. https only proves that you are talking to the right server; whoever took control of that server could rewrite the packages and the fingerprints published next to them. The signature depends on a private key that is not on that server.

In a computer lab, the teacher reads the fingerprint aloud at the start of the semester: the question is settled for everyone.

Check the key before the repository line, as on the RPM side (§ 1.B). As soon as signed-by= names the file, apt believes what it contains.

git.launchpad.net usually answers 200, but about one time in six it redirects (302) to its login page, and curl then saves that answer in the file. Do not add -L: it would follow the redirect and save the login page, a failure that looks like a success.

If gpg --show-keys prints something else, or nothing, fetch the key again. In a deployment script, repeat the curl until gpg --show-keys prints the fingerprint. apt does not need gnupg to check the repository; you need it, to read what you fetched.

The packages

apt install marionnet installs the application and the 64-bit kernel: marionnet-kernels is a recommendation (Recommends:), which apt follows by default. --no-install-recommends lets you do without it. The images remain suggestions (Suggests:): several gibibytes are a choice.

On the RPM side (§ 1.B), dnf install marionnet brings only the application. dnf silently skips the weak dependency on the kernel (which pulls in glibc.i686): that channel therefore leaves it as a suggestion, and says so after the installation. In both cases, the message shown after the installation measures what is still missing and names it.

Without an image, no virtual machine starts. Guignol is the only packaged image; the Debian images (wheezy, trixie) come from § 2. A virtual machine needs an image and a kernel that this image declares it accepts.

An image for which no accepted kernel is installed does not appear in Marionnet. Nothing fails, no message is shown: it is simply missing from the list.

Package What it contains, and what is missing without it
marionnet-kernels the 64-bit UML kernel linux-6.12.95. Without it, the recent images (Debian trixie, fetched in § 2) are not offered
marionnet-fs-guignol the small image, machine and router, the only router image published. Without it, no router
marionnet-kernels-i386 the 32-bit UML kernel linux-6.12.95-i386. Without it, neither guignol nor wheezy is offered, nor any .mar project older than 2026

A router needs two packages. Guignol's .conf file declares SUPPORTED_KERNELS='/3.2.[6-9]/ /-i386$/', which linux-6.12.95 does not satisfy. marionnet-fs-guignol therefore needs marionnet-kernels-i386.

This 32-bit kernel in turn needs a foreign architecture enabled on your machine: its interpreter is /lib/ld-linux.so.2, and only libc6:i386 provides that file. For the router, both packages:

sudo dpkg --add-architecture i386 && sudo apt update
sudo apt install marionnet-kernels-i386 marionnet-fs-guignol

Without the foreign architecture, apt refuses the package, naming libc6:i386. Enabling it is a decision you make: that is why the 32-bit kernel is a separate package.

If a precompiled archive (§ 1.C) was already installed on this machine, /etc/marionnet/marionnet.conf already exists, and dpkg asks what to do with it. A non-interactive installation fails at that question: DEBIAN_FRONTEND=noninteractive only concerns debconf, not this dpkg question. To keep your configuration:

sudo apt install -o Dpkg::Options::=--force-confold marionnet

The package's version is then left next to it, as marionnet.conf.dpkg-dist. The two files differ on one point that matters: a package installs under /usr, an archive under /usr/local.

Whatever the method, go on to § 2 (images and kernels), then § 3 (sudoers rule) and § 4 (launch).

1.B Fedora, RHEL family and openSUSE: the dnf/zypper repository

On the RHEL family, enable EPEL. Then fetch the key, check its fingerprint and import it, declare the repository, install marionnet and the data packages. Measured on Fedora 42, Rocky Linux 10, AlmaLinux 10 and openSUSE Leap 16.

On the RHEL family, enable EPEL first: one of Marionnet's dependencies, gtksourceview3, lives there and not in the base repositories.

sudo dnf install epel-release

The test benches also enable CRB (sudo dnf config-manager --set-enabled crb). If dnf reports a dependency it cannot resolve, that is the next thing to enable. Then, on any system of this family:

# 1. the key: fetched, looked at, and only then imported
sudo install -d /etc/pki/rpm-gpg
sudo curl -o /etc/pki/rpm-gpg/RPM-GPG-KEY-marionnet \
     https://git.launchpad.net/marionnet/plain/marionnet-archive-keyring.asc
# must print the fingerprint of § 1.A
gpg --show-keys /etc/pki/rpm-gpg/RPM-GPG-KEY-marionnet
sudo rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-marionnet

# 2. the repository, then the application (Fedora and RHEL family)
sudo curl -o /etc/yum.repos.d/marionnet.repo \
     https://www.marionnet.org/download/rpm/marionnet.repo
sudo dnf install marionnet

On openSUSE, zypper does not read /etc/yum.repos.d/. After the same key step, give it the address of the repository instead of the .repo file:

sudo zypper addrepo --gpgcheck https://www.marionnet.org/download/rpm/ marionnet
sudo zypper install marionnet

Like download/apt in § 1.A, the address download/rpm always follows the current series.

The key, on this side

The key is the same as in § 1.A, in the same place, with the same precautions: the redirect to the login page one time in six, and the repeated curl in a script.

The key is looked at before rpm --import: importing is already trusting, and looking afterwards would be too late. If gpg is missing, install gnupg2 (gpg2 on openSUSE); neither dnf nor rpm needs it.

The check has another form here, not another strength. apt checks one signature on the index, which covers every package by its digest. rpm has two mechanisms, and the .repo file asks for both:

Setting What it checks
gpgcheck=1 each package, by a signature written into the package itself
repo_gpgcheck=1 the index, by the file repodata/repomd.xml.asc next to it

The .repo file names the key by a local file (gpgkey=file:///etc/pki/rpm-gpg/…), not by an address: that is why you fetch it yourself. With an address, dnf would download the key following redirects, with no way to stop it. One time in six it would get the login page, and the installation would stop on Failed to import OpenPGP keys, after downloading every package.

dnf may still show a fingerprint and ask you to accept the key: for repo_gpgcheck it keeps a keyring of its own, which rpm --import does not fill. Compare the fingerprint shown with that of § 1.A before answering yes.

The repository also provides vde2, without which Marionnet does not work and which no RPM distribution offers (checked on Rocky 9 with EPEL, CRB and epel-next, and on Fedora 42 and 44). The project compiles it from the Debian source package, and dnf finds it in the same repository: you have nothing to do. openSUSE provides its own vde2, and that is the one installed.

The data packages are the three of § 1.A, under the same names and for the same reasons. dnf installs none of them by itself:

# on openSUSE: sudo zypper install ...
sudo dnf install marionnet-kernels marionnet-fs-guignol
# not on RHEL 10, see below
sudo dnf install marionnet-kernels-i386

The 32-bit kernel needs no equivalent of dpkg --add-architecture here: these distributions install 32-bit libraries next to 64-bit ones without prior setup.

RHEL 10 has removed all 32-bit libraries: marionnet-kernels-i386 cannot be installed there. Without a 32-bit kernel, neither guignol nor wheezy, hence no router on the RHEL 10 family. This is temporary: a 64-bit router image is planned. It is also why this kernel is a separate package: its refusal does not prevent installing the rest.

Whatever the method, go on to § 2 (images and kernels), then § 3 (sudoers rule) and § 4 (launch).

1.C Any other distribution: the precompiled archive

An archive that installs anywhere, without a package manager. marionnet-install.sh picks the right one and installs it for you.

The archive is named marionnet_<version>-r<rev>_<arch>_glibc<x.y>.tar.xz. The last two fields decide everything: it runs on a machine of architecture <arch> whose glibc is at least <x.y>. It is compiled on the oldest system served (today Debian 11, glibc 2.31, as its name says); Ubuntu 18.04 and Debian 10 therefore refuse it, naming the glibc.

This form is not signed. The SHA256SUMS file, which the installer checks while downloading, proves that the archive arrived whole, not who wrote it: it comes from the same server. If that difference matters to you, take § 1.A or § 1.B.

The simplest is to let the installer pick the archive and install it:

wget https://www.marionnet.org/download/marionnet-install.sh/marionnet-install.sh
bash marionnet-install.sh --binary --with-deps

--binary needs root, and calls sudo if you are not root. To see what is published before installing anything, including what your machine would refuse and why:

bash marionnet-install.sh --binary --fetch-only --list

--list comes with a mode (--binary here): the mode says whether the application, the images, or both interest you, and the script does not guess it. Under its other name, marionnet-get-images, the mode is implicit (§ 2).

You can also install the archive by hand:

xz -dc -T0 marionnet_<...>.tar.xz | tar xf -
cd marionnet_<...>/ && sudo ./install.sh --prefix /usr/local

install.sh is the same script in both cases: the installer only runs the one that travels in the archive. It copies bin/ and share/ under the prefix, writes /etc/marionnet/marionnet.conf (which is what lets the archive live anywhere) and grants the sudoers rule (§ 3). By default it names the missing apt packages without installing anything; --with-deps installs them, --no-deps does not even look. Its --help lists the rest.

The list of packages Marionnet needs to run is in the archive, one name per line, in the file REQUIRED-PACKAGES-RUNTIME. They are Debian names, the only ones --with-deps can install. On another family, install their equivalents yourself; on Fedora and the RHEL family, prefer § 1.B, since vde2 is only found in Marionnet's own dnf repository. On a system of the Debian family, by hand:

sudo apt install $(tr '\n' ' ' < REQUIRED-PACKAGES-RUNTIME)

Whatever the method, go on to § 2 (images and kernels), then § 3 (sudoers rule) and § 4 (launch).

1.D From source

For whoever wants to modify Marionnet. It takes OCaml 5.4.1 (through opam) and camlp4; the images and the kernels still come from § 2.

Beforehand, only git and make are needed: on Debian or Ubuntu, make dependencies installs the rest (opam, the C compiler, the GTK libraries).

git clone https://git.launchpad.net/marionnet && cd marionnet
# apt packages (build and run time), opam environment and packages
make dependencies
# in every new shell: put the opam environment in the PATH
eval $(opam env)
# a fresh clone needs nothing else
dune build
# the target calls sudo itself, for the one step that needs it
make install-final-as-root

To see the steps of make dependencies one by one, run them separately: make apt-dependencies, make opam-switch, make opam-dependencies.

Two things to know:

make install-for-testing also grants the sudoers rule to your account. The doors (§ 3) cannot stay in your opam environment, which belongs to you: the target therefore copies them, as root, into /usr/local/bin, then grants block (a). It asks for your sudo password to do so. make install-for-testing WITH_SUDOERS=no installs nothing privileged.

Whatever the method, go on to § 2 (images and kernels), then § 3 (sudoers rule) and § 4 (launch).

2. The images and the UML kernels, for every method

marionnet-get-images shows the published images and kernels as a checklist, and installs what you check, where the application looks for them.

Whatever the method that installed the application:

marionnet-get-images

It is another name of marionnet-install.sh (§ 1.C), installed with the application. You need it for the Debian images; if guignol is enough for you and you installed the data packages (§ 1.A, § 1.B), you can skip it.

Run it under your own account (it calls sudo when the destination is not writable) or as root.

For a whole lab, or in a deployment script, marionnet-get-images --yes takes the whole selection without asking anything. --only <pattern> and --exclude <pattern> narrow it.

An image already installed appears checked and greyed out. The command recognises it by its modification time, which must be the one its .conf file records (the MTIME field): it is also what the UML kernel checks on the base image of a virtual machine.

Do not give --prefix after a package installation. Without --prefix, the images go where the installed Marionnet looks for them, which the command asks marionnet --paths: /usr/share/marionnet/... for a package, /usr/local/share/marionnet/... for an archive. A --prefix typed by hand puts the images in a directory the application never reads. Nothing fails, and the images do not appear.

The two large images, Debian wheezy and Debian trixie, are kept out of apt and dnf on purpose: they weigh several gibibytes. The small guignol image and the kernels also exist as packages (§ 1.A, § 1.B), if you prefer your package manager to take care of them.

A computer lab without Internet access. Make a copy (a mirror) of the publication directory once. The file SHA256SUMS lists everything it contains, and serves the installer as a catalogue:

# once, on a machine that has Internet access (about 1.5 GiB, compressed)
U=https://www.marionnet.org/download/marionnet-install.sh/1.0.x
mkdir -p /srv/marionnet-mirror && cd /srv/marionnet-mirror
wget "$U/SHA256SUMS"
awk -v u="$U" '{ print u "/" $2 }' SHA256SUMS | wget -i -
sha256sum -c SHA256SUMS

Then point every machine at that copy: the installer accepts a local directory as it does an address. --fetch-only installs every published kernel and image (about 7 GiB once unpacked), and marionnet-install.sh is installed with the application, whatever the method:

# --yes: no confirmation asked, for a deployment script
marionnet-install.sh --fetch-only --from /srv/marionnet-mirror --yes

3. The sudoers rule, for every method

Marionnet creates its network interfaces with iproute2, which needs a sudoers rule. No package sets it: a package cannot know which accounts the machine is meant for. The administrator grants it once.

As administrator:

sudo marionnet-sudoers.sh install <login>...

This command grants block (a), without which Marionnet cannot create any network interface. The install.sh of the precompiled archive grants it for you (unless given --no-sudoers), as does make install-for-testing (§ 1.D). To remove everything: sudo marionnet-sudoers.sh uninstall.

The rule allows doors, not commands. None of the three blocks names ip, iptables or sysctl. Each names a door, which accepts only a closed list of actions, and which checks its arguments as root before acting.

Block Door Actions allowed
(a) marionnet-tap.sh, and marionnet-tun-device.sh (which makes /dev/net/tun usable on a host where it is not) 4, plus 1
(b) marionnet-natbridge.sh priv, plus marionnet-dnsmasq.sh (the DHCP and DNS service) and marionnet-ipv6.sh 24, plus 3 and 2
(c) marionnet-lanbridge.sh priv 12

Marionnet's interfaces and bridges carry a process number in their name. The former rules therefore had to put a * inside an argument. But sudo-rs, the sudo of Ubuntu 26.04, rejects the whole file as soon as it meets one: measured on ubuntu:26.04, each of those rules refused, nothing installed. The doors solved the problem.

A door must belong to root, and so must every directory above it. A NOPASSWD rule naming a script its owner can replace gives a root shell to that owner. install therefore refuses in that case, naming the faulty path and the chown or chmod that would fix it.

A precompiled archive installed in your home directory cannot receive the rule as it is: its doors are under a directory that belongs to you. print and check still work there, and show the rules with the refusal written into them.

3.1 Granting: one account, several, or a whole classroom

Each install adds to the permissions already given: granting a second person takes nothing away from the first. sudo marionnet-sudoers.sh uninstall <login> removes one permission and leaves the others. An account that does not exist is refused: sudoers would accept it, and the right would go to the first account later created under that name.

You can grant an account, or a group, written as in sudoers (%group). That is what a computer lab needs: whoever prepares it does not yet know the students' accounts.

# if the site has no group of its own yet
sudo groupadd marionnet
# each account (or use the existing LDAP/AD group)
sudo gpasswd -a <login> marionnet
sudo marionnet-sudoers.sh install %marionnet

Every member of the group is then allowed, including whoever joins next week. Students without sudo rights will also need the NAT bridge, granted in advance (§ 3.3).

ALL (everyone) is refused: it would include the system accounts, and what a file grants must have been decided by someone. Up to version 1.0.423, a member of an allowed group could also create an interface belonging to someone else. That is no longer possible: the owner of the interface is the account that sudo names as the caller.

Checking a permission. sudo -l -U <login> gives the effective rights of an account. marionnet-sudoers.sh check only knows the accounts and groups the file names: a member of an allowed group is not one of them. Without arguments, check answers about the file through its exit code:

Code What it means
0 the file is up to date for the accounts it names
1 nothing is granted
4 granted, but written by an older version of Marionnet; check --explain lists the commands an update would gain and lose, and marionnet-sudoers.sh install updates without removing anyone's right
5 the file is right, but sudo does not apply it (below)

Code 5. In sudoers, the last rule that matches wins. A broader rule read after ours cancels every one of our NOPASSWD lines without changing a byte of our file.

A file /etc/sudoers.d/student contains student ALL=(ALL:ALL) ALL. It is read after marionnet (alphabetical order), and sudo asks for a password at each of Marionnet's actions. Reinstalling changes nothing; renaming the broad file so that it is read first solves the problem, since our rules then come last and win:

# find the broad rule
sudo -ll ; ls /etc/sudoers.d/
sudo mv /etc/sudoers.d/student /etc/sudoers.d/00-student

check asks sudo itself, once per block, because the winning rule is decided file by file: a neighbour read after marionnet-lanbridge cancels the LAN bridge and nothing else. It does so by running a harmless action of that block's door. sudo -l would not do: it says whether an account may run the command, not whether it may without a password.

3.2 The three blocks, and what each one does to this machine

To read before granting anything beyond block (a). The three blocks are three files in /etc/sudoers.d/, granted at different times, and they do not have the same effects on the host machine.

Block Granted What it allows doing to the host machine
(a) interfaces of the virtual machines at installation, by the administrator Create and destroy mtap* interfaces, give them the address 172.23.0.254/32 and route 172.23.* to them.
(b) NAT bridge when used, from Marionnet Build a private bridge mnbr*, and translate the addresses (NAT) of the virtual machines behind it.
(c) LAN bridge when used, from Marionnet Put the network card of the host machine into a bridge, to place the virtual machines on the real local network.

(a), in detail. The block only touches mtap* interfaces, and the door checks it, as root: the four actions of marionnet-tap.sh check the name they are given, and the owner of the interface is the account that sudo names as the caller, not an argument. These interfaces are also the path of the graphical applications of the virtual machines: an xterm, or above all a wireshark started inside a virtual machine to watch its own traffic, shows up on the host's screen through this path. Marionnet opens it with xhost +172.23.0.254. Without this block, no graphical application opens from the virtual machines. Routers have no graphical applications: traffic is watched there with tcpdump.

(b), in detail. The block:

IPv6 forwarding is not set interface by interface: enabling it turns the whole host machine into a router, and a router ignores the advertisements it receives. A tiny door without arguments, marionnet-ipv6.sh, therefore saves the value of accept_ra and restores it.

The host's card, its addresses and its routes are never named in this block: it cannot touch them.

(c), in detail: it is the network of the host machine, and it cannot be fenced in. A LAN bridge enslaves the host's card to the bridge mnlan0. The host's IPv4 address and default route move onto the bridge, which also takes the card's MAC address. There is a single one per machine (a card has only one master bridge), and two Marionnet sessions share it.

To weigh before granting (c):

In plain words, this block lets an account move the machine's IPv4 address and default route onto a bridge, one card at a time, as long as that bridge claims it. There is no iptables, no NAT, and no IPv6 (not handled at all).

Wi-Fi is refused: an access point does not answer several MAC addresses behind a single association. Also refused: a card already enslaved to someone else's bridge, and an ambiguous default route.

3.3 Granting (b) without (c)

This is the default, and there is nothing to do to get it. An install without options grants only (a), and the bridge blocks are never granted at installation. When a user starts a NAT bridge or a LAN bridge, Marionnet asks for their own sudo password, and installs the block. Block (c) is therefore reserved to the accounts that have sudo rights.

To give a lab the NAT bridge in advance, without a password and without ever granting (c):

sudo marionnet-sudoers.sh install --enable-natbridge %marionnet

This command also grants (a): it is the only one needed. To remove a block and keep (a):

# for every account
sudo marionnet-sudoers.sh uninstall --disable-natbridge
# for one account
sudo marionnet-sudoers.sh uninstall --disable-natbridge <login>

3.4 Forbidding a block outright

Removing a permission does not stop the next user from asking for it again from Marionnet, with their own password. An administrator who wants no LAN bridge on this machine, ever and for anyone, says so once:

sudo marionnet-sudoers.sh deny --lanbridge     # or --natbridge, or --bridges

As long as this ban is in place:

sudo marionnet-sudoers.sh allow --lanbridge lifts the ban, without granting anything: a user must still ask. Anyone can check the state, without privileges:

# exit code 0 if the block is allowed, 3 if it is forbidden; it says which
marionnet-sudoers.sh policy

The ban is a file in /etc/marionnet/, readable by everyone on purpose: Marionnet must know the answer before asking for a password, and the files in /etc/sudoers.d/ are readable by root only.

Block (a) has no ban: the administrator grants it by hand, and not typing the command is enough. A ban stops a mistake, not a determined administrator, who can always edit /etc/sudoers.d/. It is useful in the usual setup of a lab, with a teacher who has sudo rights and students who do not: that is where a LAN bridge gets built by accident.

4. Launch Marionnet, and check the installation

marionnet                    # or: marionnet -r lab.mar, marionnet --exam, marionnet --help

marionnet is the name all the pages of this documentation use. It is a symbolic link to marionnet.native, the name dune install gives the executable: the same program.

To know whether this installation is the one you think it is, whatever the method:

marionnet -v                 # version and revision
marionnet --paths            # where this installation looks for images, kernels and scripts

If the images do not appear, --paths shows the directories where the installation really looks for them (§ 2).

To know whether anything is left to do, the command is the one the apt and dnf packages run after installation; you may already have read its output:

# as root, so that the sudoers file is examined too
marionnet-setup-check.sh

It says nothing when nothing is missing. Otherwise it names what is missing: the state of the sudoers rule (§ 3.1), the missing images and kernels, the command that would fetch them. On an outdated permission, it shows the commands an update would gain and lose, on this machine.

5. Removing Marionnet

In all three cases, removal leaves in place:

6. When something does not work

What you see What it is
server down, no route, wrong URL?, while the site answers no certificates: § 1
apt says the repository is ignored, and apt-get update still returns 0 same cause, or the repository line was edited; apt only reports it as a warning
Missing key <fingerprint>, or signature verification failed the file in /etc/apt/keyrings/ is not the archive key: fetch it again (§ 1.A) and compare the fingerprint
apt still offers the package although it just refused the repository it reuses the old index: sudo rm -rf /var/lib/apt/lists/* then sudo apt update
Failed to import OpenPGP keys, or dnf announces a repository without packages the key file of § 1.B is missing, was not accepted, or is not a key: fetch it again and check the fingerprint before importing it
the precompiled archive is refused, naming a glibc your distribution is older than the build system: § 1.C
marionnet-kernels-i386 is refused, naming libc6:i386 dpkg --add-architecture i386: § 1.A
Marionnet starts, but the images do not appear they are under a prefix the application does not read: § 2, then marionnet --paths
Unsatisfied dependency at startup vde2 or graphviz is missing; the archive's install.sh names what is missing, --with-deps installs it
a virtual machine refuses to start, the interfaces cannot be created the sudoers rule: § 3
nothing opens when wireshark or xterm is started inside a virtual machine block (a) is not granted (§ 3.2), or the host has no X display
marionnet-sudoers.sh install refuses, naming a path and an owner a door must belong to root, with all its parent directories: § 3. Typical of an installation in a directory that belongs to you
the rule is installed, and sudo still asks for a password a broader rule in /etc/sudoers.d/ is read after ours and wins: § 3.1, code 5
visudo or sudo rejects the whole file on Ubuntu 26.04 rules written by a Marionnet older than the doors: sudo marionnet-sudoers.sh install <login> rewrites them (§ 3)
the check keeps saying the permission is outdated, whatever you do a Marionnet older than the one of this page, on an RPM distribution: its check needed diff, absent from those systems. Update Marionnet

Where to go next

These pages are installed next to this one. They are in the doc-src/ directory of the source repository, which also publishes the archive key of § 1.A and § 1.B:

git clone https://git.launchpad.net/marionnet
Page Read it to
INSTALL.FR.md read this page in French
teacher-guide.md prepare a lab, run the session, grade it
scripting/README.md drive Marionnet from a script
exam-mode.md see what an exam session records
project-format-v3.md know the format of .mar projects