Configuring Embedded Linux Networking
Static IP, DHCP, and glibc name resolution for your root filesystem in this free linux development course
A root filesystem that boots but cannot reach the network is only half finished for most embedded products today. This lecture in our free linux development course covers the two pieces you need for a working network stack on a minimal BusyBox-based image: interface configuration for both static and DHCP-assigned addresses, and glibc’s name service switch, which controls how hostnames and usernames get resolved to numbers. We build on the earlier device-node and daemon setup from this chapter, since networking depends on having /proc, /sys, and a working init sequence already in place.
What You Will Learn
Prerequisites
Your rootfs should already have BusyBox built with the networking applets (ifconfig, udhcpc) enabled, and a working init sequence that mounts proc, sysfs, and devtmpfs as covered in the previous lecture.
Two Layers of Network Setup
Getting an embedded device onto the network involves two mostly independent layers. The first is bringing up the interface itself — assigning it an IP address, netmask, and default route, either statically or via DHCP. The second, easy to overlook, is name resolution — how the C library turns hostnames into IP addresses and usernames into UIDs. Both need to be configured for a typical networked application to work correctly.
Bringing Up the Interface with ifupdown
BusyBox includes minimal ifup and ifdown implementations that read a single configuration file, /etc/network/interfaces. Before writing that file, create the supporting directory structure in your staged rootfs:
$ mkdir -p etc/network/if-pre-up.d
$ mkdir -p etc/network/if-up.d
$ mkdir -p var/run
Static IPv4 Configuration
For a fixed address, list the loopback interface and your Ethernet interface together in /etc/network/interfaces:
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address 192.168.1.50
netmask 255.255.255.0
gateway 192.168.1.1
The auto lines tell ifup -a which interfaces to bring up automatically at boot; anything not listed with auto has to be brought up manually with ifup <name>.
Dynamic Configuration with DHCP
Swapping static for dhcp hands the interface over to a DHCP client instead:
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
BusyBox’s DHCP client, udhcpc, does not configure the interface itself — it runs a shell script every time it acquires, renews, or loses a lease, and that script is responsible for actually calling ifconfig and writing /etc/resolv.conf. The script lives at /usr/share/udhcpc/default.script and must be executable. A minimal version that handles the common events looks like this:
#!/bin/sh
# ep_udhcpc_handler - minimal DHCP event handler for BusyBox udhcpc
case "$1" in
deconfig)
ifconfig "$interface" 0.0.0.0
;;
bound|renew)
ifconfig "$interface" "$ip" netmask "$subnet"
[ -n "$router" ] && route add default gw "$router" "$interface"
if [ -n "$dns" ]; then
: > /etc/resolv.conf
for ns in $dns; do
echo "nameserver $ns" >> /etc/resolv.conf
done
fi
;;
esac
exit 0
$ chmod +x usr/share/udhcpc/default.script
glibc’s Name Service Switch
Once the interface can send and receive packets, applications still need a way to turn names into numbers — resolving a hostname to an IP address, or a username to a UID. On a glibc-based rootfs this is controlled by the Name Service Switch (NSS), configured through /etc/nsswitch.conf. A configuration suitable for most embedded systems looks like this:
passwd: files
group: files
shadow: files
hosts: files dns
networks: files
protocols: files
services: files
Each line names a database and the order of sources glibc should consult. With hosts: files dns, glibc checks /etc/hosts first, then falls back to an actual DNS lookup if the name is not found locally.
Populating /etc
/etc/networks, /etc/protocols, and /etc/services are the same on every Linux system, so the simplest approach is to copy them straight from your build host:
$ cp /etc/protocols etc/
$ cp /etc/services etc/
/etc/hosts needs at minimum the loopback entry:
127.0.0.1 localhost
/etc/passwd, /etc/group, and /etc/shadow are specific to your target’s user accounts and are covered separately in this course’s user-accounts lecture.
Copying the NSS Plugin Libraries
The libraries that actually implement each NSS lookup source are loaded as runtime plugins based on nsswitch.conf, which means static analysis tools like readelf will not show them as dependencies of any binary — they simply will not be found unless you copy them explicitly from your toolchain’s sysroot:
$ cd ~/rootfs
$ cp -a $TOOLCHAIN_SYSROOT/lib/libnss* lib/
$ cp -a $TOOLCHAIN_SYSROOT/lib/libresolv* lib/
Skipping this step is one of the most common causes of a target that can ping an IP address but fails to resolve any hostname.
| File | Purpose | Source |
|---|---|---|
| /etc/network/interfaces | Interface bring-up config | Hand-written |
| /usr/share/udhcpc/default.script | DHCP lease event handler | Hand-written or BusyBox example |
| /etc/nsswitch.conf | NSS lookup order | Hand-written |
| /etc/protocols, /etc/services | Protocol/port name tables | Copied from build host |
| lib/libnss*, lib/libresolv* | NSS plugin implementations | Copied from toolchain sysroot |
Build-and-Boot Walkthrough
$ qemu-system-arm -M virt -kernel zImage -initrd rootfs.cpio.gz \
-append "console=ttyAMA0" -netdev user,id=n0 -device virtio-net-device,netdev=n0 -nographic
# ifup -a
# ifconfig eth0
eth0 Link encap:Ethernet
inet addr:192.168.1.50 Bcast:192.168.1.255 Mask:255.255.255.0
# ping -c1 example.com
PING example.com (93.184.216.34): 56 data bytes
64 bytes from 93.184.216.34: seq=0 ttl=54 time=41.2 ms
Common Mistakes and Troubleshooting
- Missing or non-executable default.script — udhcpc will acquire a lease but never actually configure the interface if the script is missing its execute bit.
- Forgetting the NSS plugin libraries — DNS lookups fail silently or with “Unknown host” even though
/etc/resolv.confis correct. - Empty /etc/hosts — without the loopback entry, some applications that expect to resolve “localhost” will fail at startup.
- Wrong interface name — always confirm the actual interface name with
ip linkorifconfig -arather than assuming eth0 on boards with multiple MAC controllers.
Best Practices
Keep your DHCP handler script minimal and readable — most failures in embedded DHCP setups come from an overcomplicated script, not from udhcpc itself. For products deployed on untrusted networks, consider restricting hosts: files dns to hosts: files with a curated static hosts file if DNS is not actually required, reducing attack surface.
Summary and Key Takeaways
Interface configuration and name resolution are two separate concerns: /etc/network/interfaces plus a DHCP handler script bring up the link, while nsswitch.conf plus the copied NSS plugin libraries let glibc actually resolve names once you are online.
Conclusion
Networking is often the last thing embedded developers get right on a new rootfs, mainly because failures are silent — a missing library or an unexecutable script does not crash boot, it just quietly breaks connectivity. With the pieces in this lecture in place, your image will both bring up an interface correctly and resolve names once it is online, rounding out another core skill in this free embedded systems course.
Frequently Asked Questions
Why does udhcpc get a lease but my interface never gets configured?
udhcpc only acquires the lease; the actual ifconfig call happens inside the script at /usr/share/udhcpc/default.script. Check that the file exists and is executable.
Do I need both /etc/hosts and DNS configured?
At minimum you need the loopback entry in /etc/hosts. Whether you also need DNS depends on whether your applications resolve external hostnames.
Why do hostname lookups fail even though resolv.conf looks correct?
This is almost always a missing libnss* or libresolv* library — they load as runtime plugins and will not show up as a linked dependency of any binary.
Can I use static IP and DHCP on different interfaces at the same time?
Yes, /etc/network/interfaces supports a separate iface stanza per interface, so one can be static while another uses DHCP.
Is ifupdown the only option for embedded network configuration?
No, some products use systemd-networkd or a custom init script instead; ifupdown is simply the lightest-weight option that pairs naturally with BusyBox.
What NSS databases matter most for a typical embedded product?
passwd, group, and hosts cover the vast majority of embedded use cases; shadow, networks, protocols, and services matter mainly if you run standard networking daemons.
Continue the Free Linux Development Course
Next up: creating filesystem images with device tables for jffs2, ubifs, and ext2.
Next Lecture Browse the Full Course
2 Comments