Networking

The built-in user network gives the guest DHCP, DNS and outgoing TCP. In Node it uses real sockets; in a browser, a relay.

The guest gets a virtio network card and, behind it, a small router built into Warm64: QEMU's user network. It hands out an address by DHCP, answers DNS, and carries the guest's outgoing TCP connections.

wemu-system-aarch64 ... -netdev user,id=n0 -device virtio-net-pci,netdev=n0
# or, in one option
wemu-system-aarch64 ... -nic user

The user network

AddressWhat
10.0.2.15The guest (by DHCP)
10.0.2.2The gateway. TCP to it reaches the host's 127.0.0.1.
10.0.2.3DNS

What it carries:

  • DHCP, ARP, and ping to the gateway and DNS addresses.
  • DNS A lookups, answered by the host.
  • Outgoing TCP, to any address, opened by the host.

What it doesn't: connections into the guest (hostfwd is refused), UDP other than DHCP and DNS, and IPv6.

In the guest

On Alpine's netboot initramfs:

modprobe virtio_net
udhcpc -i eth0
echo nameserver 10.0.2.3 > /etc/resolv.conf
wget -O - http://example.com/

Most installed systems configure the network by DHCP on their own.

In Node

nodeWEMUHost(), and so wemu-system-aarch64, opens the guest's TCP connections as real sockets and answers DNS with the system's resolver. The guest reaches the internet, and your machine's local services at 10.0.2.2.

In a browser

A web page can't open raw TCP connections, so the guest's connections travel over a WebSocket to a relay, a small Node program that opens them for it. webSocketConnector() is the browser end:

import { WEMU, browserWEMUHost, webSocketConnector } from "warm64";

const host = {
  ...browserWEMUHost(),
  connector: webSocketConnector("wss://relay.example.com/"),
  resolve: async (name) => lookUp(name),   // your DNS, returning an IPv4 address or null
};

The Warm64 repository includes one, examples/net/tcp-relay.mjs, which takes a port and an allow-list of the hosts and networks the guest may reach:

ALLOW="example.com:443,10.0.0.0/8" node examples/net/tcp-relay.mjs 7682

Warning A relay opens connections on the guest's behalf. Run it with an allow-list, or anyone who can reach it can use it as a proxy.

Without a connector, the guest still gets DHCP, ARP and ping, but its TCP connections are refused. Without resolve, every name lookup fails.

Guests on one network

-netdev socket,connect= joins the guest to an Ethernet hub over a WebSocket, so several machines, in different pages or processes, share a network. The repository's examples/net/relay-hub.mjs is such a hub:

node examples/net/relay-hub.mjs 7681
wemu-system-aarch64 ... -netdev socket,id=n0,connect=ws://localhost:7681 -device virtio-net-pci,netdev=n0

There's no DHCP on the hub: give each guest its own address on the same subnet.

set_link (in QMP and the monitor) takes a network card's link down and up again:

await vm.qmp("set_link", { name: "net0", up: false });

See also