Understanding and Securing systemd-resolved: Interface Binding Analysis and Hardening for IoT Devices


2 views

The systemd-resolved service serves as a modern DNS resolver for Linux systems, implementing several key features:

  • DNS stub resolver (listening on 127.0.0.53:53 by default)
  • LLMNR (Link-Local Multicast Name Resolution) responder
  • mDNS (Multicast DNS) responder (port 5355)
  • DNS-over-TLS support
  • DNSSEC validation
# To view active services:
$ systemctl status systemd-resolved
● systemd-resolved.service - Network Name Resolution
   Loaded: loaded (/usr/lib/systemd/system/systemd-resolved.service; enabled)
   Active: active (running) since Thu 2023-11-16 14:20:43 UTC; 1h ago

The service binds to 0.0.0.0:5355 specifically for mDNS/LLMNR functionality, which requires:

  1. Multicast traffic handling across all interfaces
  2. Local network service discovery
  3. Link-local name resolution

For regular DNS resolution, it uses 127.0.0.53:53 (stub resolver) which doesn't expose externally.

While mDNS on 0.0.0.0 is by design, it can present risks in IoT environments:

# Check listening ports:
$ sudo ss -tulnp | grep resolved
udp   UNCONN 0      0            0.0.0.0:5355         0.0.0.0:*    users:(("systemd-resolve",pid=240,fd=13))

Hardening recommendations:

# Disable mDNS (add to /etc/systemd/resolved.conf):
[Resolve]
MulticastDNS=no

# Restrict LLMNR:
LLMNR=no

# Then restart:
$ sudo systemctl restart systemd-resolved

Disabling systemd-resolved would:

Feature Impact
DNS Caching Applications would query upstream directly
DNSSEC Validation would need handling at application level
mDNS Local service discovery would break

For headless IoT devices, consider:

# Minimal /etc/systemd/resolved.conf:
[Resolve]
DNS=8.8.8.8 1.1.1.1
FallbackDNS=
Domains=
LLMNR=no
MulticastDNS=no
DNSSEC=allow-downgrade
Cache=yes
DNSStubListener=yes

This maintains core DNS functionality while reducing attack surface.

After configuration changes:

# Verify settings:
$ resolvectl status
Global
       LLMNR setting: no
    MulticastDNS setting: no
  DNSOverTLS setting: no
      DNSSEC setting: allow-downgrade
    DNSSEC supported: yes

# Test resolution:
$ drill example.com @127.0.0.53
;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 12345
;; flags: qr rd ra ; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;; example.com.   IN  A

;; ANSWER SECTION:
example.com.   86399   IN  A   93.184.216.34

For IoT devices specifically, also check with:

# Check open ports from network perspective:
$ nmap -sU -p 5355 [device_ip]

systemd-resolved is a critical system service in modern Linux distributions that handles DNS resolution for local applications. It acts as a local DNS stub resolver, caching DNS responses and implementing features like DNSSEC validation and DNS-over-TLS. Unlike traditional resolvers, it integrates tightly with systemd's network management.

The service listens on all interfaces (0.0.0.0) primarily for two reasons:

  1. To respond to mDNS (multicast DNS) and LLMNR (Link-Local Multicast Name Resolution) queries on port 5355
  2. To provide DNS resolution for containers and virtual machines that might use different network interfaces

Here's how you can verify the listening ports:

sudo ss -tulnp | grep systemd-resolved
# Output example:
# udp    UNCONN   0      0              0.0.0.0:5355         0.0.0.0:*     users:(("systemd-resolved",pid=240,fd=12))
# tcp    LISTEN   0      4096           0.0.0.0:5355         0.0.0.0:*     users:(("systemd-resolved",pid=240,fd=13))

While listening on all interfaces is by design, it does present potential security concerns:

  • Exposure to local network attacks if the device has multiple interfaces
  • Potential information leakage through DNS queries
  • Attack surface for DNS-based vulnerabilities

For IoT devices like the Intel Galileo, this is particularly concerning as they often operate in less secure environments.

Here are several approaches to secure the service:

1. Restrict Listening Interfaces

Edit the systemd-resolved configuration file:

sudo nano /etc/systemd/resolved.conf

Add or modify these lines:

[Resolve]
DNSStubListener=udp:127.0.0.1:53
DNSStubListenerExtra=udp:192.168.1.100:5355  # Replace with your specific IP
MulticastDNS=no
LLMNR=no

2. Disable Unnecessary Features

For IoT devices, you might want to disable features you don't need:

[Resolve]
DNSSEC=allow-downgrade
Cache=no
DNSOverTLS=opportunistic

3. Firewall Rules

Add specific iptables rules to restrict access:

sudo iptables -A INPUT -p udp --dport 5355 -i lo -j ACCEPT
sudo iptables -A INPUT -p udp --dport 5355 -j DROP

If you choose to disable the service completely:

sudo systemctl disable --now systemd-resolved

Be aware of these potential impacts:

  • Applications using glibc's getaddrinfo() will fall back to /etc/resolv.conf
  • Loss of DNS caching may increase network latency
  • DNSSEC validation will need to be handled elsewhere
  • Some systemd-networkd features may not work properly

For resource-constrained IoT devices, consider this minimal configuration:

[Resolve]
DNS=8.8.8.8 1.1.1.1
DNSStubListener=no
FallbackDNS=
Domains=
LLMNR=no
MulticastDNS=no
DNSSEC=no
Cache=no

Remember to update your /etc/resolv.conf if you make significant changes:

sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf

After making changes, verify with these commands:

systemd-resolve --status
dig example.com
systemd-analyze security systemd-resolved.service