Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Networking

The guest has one Ethernet interface. By default it is configured with DHCP; static addresses come from the kernel command line.

Command lineDefaultMeaning
uniapp.ip=A.B.C.D/NDHCPaddress and prefix for the first NIC
uniapp.gw=A.B.C.Dfrom DHCPdefault route
uniapp.dns=A.B.C.Dfrom DHCPnameserver
ip=dhcp(Asterinas only)run the kernel’s DHCP client instead of the built-in 10.0.2.15/24

Under QEMU user-mode networking (-netdev user) DHCP yields 10.0.2.15, gateway 10.0.2.2 and the DNS forwarder 10.0.2.3; the make run-* targets rely on that. If DHCP fails, /init falls back to exactly those values.

How the interface is configured

On Linux /init runs a small DHCPv4 client over an AF_PACKET socket (DISCOVER, OFFER, REQUEST, ACK; five attempts with backoff), then applies the lease with the classic ioctls SIOCSIFADDR, SIOCSIFNETMASK, SIOCSIFFLAGS and SIOCADDRT. The interface name is discovered from /sys/class/net, falling back to eth0.

Asterinas has no AF_PACKET sockets, so there the kernel does DHCP: ip=dhcp on the command line (the Linux ip= parameter) starts smoltcp’s DHCPv4 client on eth0 and publishes the lease in /proc/net/dhcp as eth0 10.0.2.15/24 10.0.2.2 dns 10.0.2.3 (or eth0 pending). /init waits up to 30 s for that line and takes the nameserver from it; the address and route are already installed. Without ip=dhcp Asterinas keeps its compiled-in 10.0.2.15/24 via 10.0.2.2, which /init may override with uniapp.ip=: the set-ioctls work since patch 0003. The log line tells you which path ran: (kernel dhcp), (dhcp), (static) or (default).

Name resolution

OTP’s default lookup method on Unix is native, which spawns the port program inet_gethost. That binary is not in the image, so /init writes /etc/inetrc:

{lookup, [file, dns]}.
{host, {127,0,0,1}, ["localhost"]}.
{edns, 0}.

and points ERL_INETRC at it. Lookups then go through inet_res, OTP’s resolver written in Erlang, which reads nameservers from /etc/resolv.conf. /init writes that file from uniapp.dns. Keep both files: inet_db re-reads resolv.conf periodically and a missing file clears the nameserver list.

:inet.gethostbyname/1, :gen_tcp.connect(~c"host", ...), :httpc, Req, Finch and friends all work through this path.

TLS

OpenSSL 3.5 is statically linked into beam.smp, so :crypto, :ssl and :public_key are available without any files. For verifying servers, the image ships Alpine’s CA bundle at /etc/ssl/cacert.pem:

:ssl.connect(~c"www.erlang.org", 443,
  verify: :verify_peer,
  cacertfile: ~c"/etc/ssl/cacert.pem",
  versions: [:"tlsv1.3"],
  server_name_indication: ~c"www.erlang.org")

For a TLS server, generate a certificate at boot (the sample app uses :public_key.pkix_test_data/1 with digest: :sha256; SHA-1 signed test certificates are rejected by modern clients) or ship a certificate and key in priv/ of your release.

Reaching the guest from the host

With QEMU user networking the guest is not routable from the host; use port forwards. The Makefile forwards host 14000, 14001 and 14443 to guest 4000 (TCP), 4001 (UDP) and 4443 (TCP). Add more in QEMU_BASE, or switch to a tap device for a real bridged network.

Known gaps on Asterinas

  • Binding to 0.0.0.0 attaches the socket to the NIC only, so traffic to 127.0.0.1 does not reach a socket bound to the wildcard address. Bind explicitly to 127.0.0.1 for loopback-only servers. This comes from the local patch that makes wildcard binds work at all; see Asterinas patches.
  • :inet.getifaddrs/0 works on Asterinas main but returned {:error, :eaddrnotavail} on v0.18.1.
  • IPv6 is untested.