Minimise services and packages

Find every listener, remove what you do not need.

Intermediate14 min · lesson 2 of 24

After patching, the cheapest control is to run less. A listening socket is code that anyone who can reach the port can talk to, and every installed package is code that can carry a vulnerability or help an intruder who is already in. In this lesson you take an inventory of what a server exposes, trace each listener to the unit, package and setting behind it, switch off what is not needed at the right strength, bind what must stay to the local machine, and check the result from another host instead of trusting the configuration.

What a fresh install exposes

Linux essentials showed how to read sudo ss -tulpn: 0.0.0.0 and [::] mean every address the machine has, 127.0.0.x and [::1] only the machine itself, and %eth0 one interface. Here is the baseline of an untouched install.

deploy@web01 · Ubuntu 26.04 LTS (default install)
$ sudo ss -tulpn
Netid State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess udp UNCONN 0 0 0.0.0.0:5353 0.0.0.0:* users:(("systemd-resolve",pid=471,fd=13)) udp UNCONN 0 0 127.0.0.54:53 0.0.0.0:* users:(("systemd-resolve",pid=471,fd=21)) udp UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=471,fd=19)) udp UNCONN 0 0 192.168.5.15%eth0:68 0.0.0.0:* users:(("systemd-network",pid=775,fd=36)) udp UNCONN 0 0 127.0.0.1:323 0.0.0.0:* users:(("chronyd",pid=930,fd=4)) udp UNCONN 0 0 [::]:5353 [::]:* users:(("systemd-resolve",pid=471,fd=14)) udp UNCONN 0 0 [::1]:323 [::]:* users:(("chronyd",pid=930,fd=5)) tcp LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=471,fd=20)) tcp LISTEN 0 4096 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=882,fd=3),("systemd",pid=1,fd=260)) tcp LISTEN 0 4096 127.0.0.54:53 0.0.0.0:* users:(("systemd-resolve",pid=471,fd=22)) tcp LISTEN 0 4096 [::]:22 [::]:* users:(("sshd",pid=882,fd=4),("systemd",pid=1,fd=261))

On this untouched Ubuntu Server 26.04 install, SSH on TCP 22 is open to the network; systemd appears next to sshd because ssh.socket holds the port (socket activation, from Linux essentials). The DHCP client of systemd-networkd uses UDP 68 on eth0 to get the address. Everything else is loopback: the systemd-resolved DNS stub on 127.0.0.53 and 127.0.0.54, and chrony's command port 323. The exception is UDP 5353 (multicast DNS) on every address, and it is not Ubuntu's doing, as the next section shows. So the network-facing surface of a default install is SSH and the DHCP client, which is a good starting point.

ss covers only TCP and UDP; systemctl list-sockets shows every socket unit. As Linux essentials explained, systemd-ssh-generator adds sshd on AF_VSOCK port 22 inside a VM (reachable only from the hypervisor host, which on a cloud VM is your provider's) and a local Unix socket; systemd.ssh_auto=no on the kernel command line turns that off (systemd-ssh-generator(8)).

deploy@web01 · Ubuntu 26.04 LTS (default install)
$ systemctl list-sockets
LISTEN UNIT ACTIVATES 0.0.0.0:22 ssh.socket ssh.service … [::]:22 ssh.socket ssh.service … vsock::22 sshd-vsock.socket sshd@3-2-3:22-2:1612536735.service … /run/ssh-unix-local/socket sshd-unix-local.socket - …

Services that do not listen still matter, because each is code running on your server. List what runs:

deploy@web01 · Ubuntu 26.04 LTS (default install)
$ systemctl list-units --type=service --state=running
UNIT LOAD ACTIVE SUB DESCRIPTION chrony.service loaded active running chrony, an NTP client/server cron.service loaded active running Regular background program processing daemon dbus.service loaded active running D-Bus System Message Bus fwupd.service loaded active running Firmware update daemon getty@tty1.service loaded active running Getty on tty1 lima-guestagent.service loaded active running lima-guestagent ModemManager.service loaded active running Modem Manager multipathd.service loaded active running Device-Mapper Multipath Device Controller networkd-dispatcher.service loaded active running Dispatcher daemon for systemd-networkd polkit.service loaded active running Authorization Manager rsyslog.service loaded active running System Logging Service serial-getty@hvc0.service loaded active running Serial Getty on hvc0 ssh.service loaded active running OpenBSD Secure Shell server sshd@3-2-3:22-2:1612536735.service loaded active running OpenBSD Secure Shell server per-connection daemon (vsock:2:1612536735) systemd-journald.service loaded active running Journal Service systemd-logind.service loaded active running User Login Management systemd-networkd.service loaded active running Network Management systemd-resolved.service loaded active running Network Name Resolution systemd-udevd.service loaded active running Rule-based Manager for Device Events and Files udisks2.service loaded active running Disk Manager unattended-upgrades.service loaded active running Unattended Upgrades Shutdown user@502.service loaded active running User Manager for UID 502 … 22 loaded units listed.

lima-guestagent, the sshd@... vsock connection and user@502 (the tool's login session) belong to the lab's VM tool. Among Ubuntu's own services, ModemManager handles cellular modems, multipathd manages storage reached over several paths (a SAN), and udisks2 manages disks on behalf of desktop tools. A cloud VM usually needs none of them; multipathd must stay on a server whose disks are multipath. They take the same stop, disable and mask steps as the listener below.

Trace a listener to its cause

A listener you cannot explain is a finding until you can. The 5353 socket above belongs to systemd-resolved. On the working lab machine, go from the process to the unit to the configuration.

deploy@web01 · Ubuntu 26.04 LTS
$ sudo ss -ulpn sport = :5353
State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess UNCONN 0 0 0.0.0.0:5353 0.0.0.0:* users:(("systemd-resolve",pid=474,fd=13)) UNCONN 0 0 [::]:5353 [::]:* users:(("systemd-resolve",pid=474,fd=14))
$ ps -o unit= -p 474
systemd-resolved.service
$ systemd-analyze cat-config systemd/resolved.conf | grep -E '^(# /.*\.conf$|[^#])'
# /etc/systemd/resolved.conf [Resolve] # /usr/lib/systemd/resolved.conf.d/00-disable-mdns.conf [Resolve] MulticastDNS=no # /etc/systemd/resolved.conf.d/00-lima-enable-mdns.conf [Resolve] MulticastDNS=yes # /usr/lib/systemd/resolved.conf.d/cache-no-negative.conf [Resolve] Cache=no-negative

ps -o unit= turns the PID from ss into the systemd unit. systemd-analyze cat-config prints the main configuration file and every drop-in in the order they apply (the grep keeps file names and settings). Ubuntu ships 00-disable-mdns.conf with MulticastDNS=no. The VM tool adds 00-lima-enable-mdns.conf with MulticastDNS=yes, and because its name sorts later, it wins. A plain Ubuntu server does not answer multicast DNS queries from the local network; these lab machines do.

The fix is another drop-in whose name sorts last. Comments go on their own lines: systemd's configuration files do not support a comment after a value.

/etc/systemd/resolved.conf.d/99-secopslog-no-mdns.conf
[Resolve]
# SecOpsLog: no multicast DNS on servers (Ubuntu's own default).
# This file sorts after the VM tool's 00-lima-enable-mdns.conf, so it wins.
MulticastDNS=no
deploy@web01 · Ubuntu 26.04 LTS
$ sudo systemctl restart systemd-resolved sudo ss -ulpn sport = :5353
State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
$ resolvectl status | grep Protocols
Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported Protocols: +DefaultRoute -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported Protocols: -DefaultRoute -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported

ss prints only its header, and resolvectl reports -mDNS globally and on the link. The operational impact is that names ending in .local no longer resolve on this host, which a server rarely needs. To roll back, delete the file and restart systemd-resolved. The control restores Ubuntu's default; keeping it is SecOpsLog advice.

Off, and how far off

systemd gives four strengths of "off". stop ends the running process now. disable removes the links that start it at boot. mask links the unit to /dev/null, so nothing can start it: not a person, not another unit that depends on it, not a socket. Purging the package removes its files and configuration. rpcbind shows why the difference matters. It maps RPC services to ports and is needed for NFS versions 2 and 3, which is why nfs-common depends on it. The CIS RHEL 10 Level 1 server profile (scap-security-guide 0.1.82, introduced in the first lesson) includes a rule that it be disabled. To follow along, install it with sudo apt install rpcbind, as nfs-common would.

deploy@web01 · Ubuntu 26.04 LTS
$ sudo ss -tulpn sport = :111
Netid State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess udp UNCONN 0 0 0.0.0.0:111 0.0.0.0:* users:(("rpcbind",pid=267957,fd=5),("systemd",pid=1,fd=84)) udp UNCONN 0 0 [::]:111 [::]:* users:(("rpcbind",pid=267957,fd=7),("systemd",pid=1,fd=86)) tcp LISTEN 0 4096 0.0.0.0:111 0.0.0.0:* users:(("rpcbind",pid=267957,fd=4),("systemd",pid=1,fd=83)) tcp LISTEN 0 4096 [::]:111 [::]:* users:(("rpcbind",pid=267957,fd=6),("systemd",pid=1,fd=85))
$ systemctl list-unit-files 'rpcbind*'
UNIT FILE STATE PRESET rpcbind.service enabled enabled rpcbind.socket enabled enabled rpcbind.target static - 3 unit files listed.

Port 111 is open on every address, over TCP and UDP. Both rpcbind.service and rpcbind.socket are enabled, and systemd co-owns the sockets: rpcbind is socket-activated. Disable the service the obvious way:

deploy@web01 · Ubuntu 26.04 LTS
$ sudo systemctl disable --now rpcbind
Synchronizing state of rpcbind.service with SysV service script with /usr/lib/systemd/systemd-sysv-install. Executing: /usr/lib/systemd/systemd-sysv-install disable rpcbind Removed '/etc/systemd/system/multi-user.target.wants/rpcbind.service'. Removed '/etc/systemd/system/sockets.target.wants/rpcbind.socket'. Disabling 'rpcbind.service', but its triggering units are still active: rpcbind.socket Stopping 'rpcbind.service', but its triggering units are still active: rpcbind.socket
$ sudo ss -tlpn sport = :111
State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess LISTEN 0 4096 0.0.0.0:111 0.0.0.0:* users:(("systemd",pid=1,fd=269)) LISTEN 0 4096 [::]:111 [::]:* users:(("systemd",pid=1,fd=271))

The first two lines appear because rpcbind still ships an old-style init script, which systemd's helper disables as well. The unit links are removed, including the socket's, because the service names the socket under Also=. But --now stopped only the service, and systemctl says so: its triggering unit, rpcbind.socket, is still active. Port 111 is still open, now held by PID 1 alone, and the next connection would start rpcbind again. When ss shows systemd as the only owner of a port, look for a .socket unit.

Check it the way an attacker would, from another machine on the same network, such as your laptop with nmap installed (it is not on a default server; nc -zv SERVER 111 also tests one port). In the lab the other machine is a second network namespace wired to the server, which is 198.51.100.1 on that link. nmap -n -sT -p 111 makes a full TCP connection to port 111 and skips reverse DNS lookups (-n).

deploy@web01 · Ubuntu 26.04 LTS
$ sudo ip netns exec hard-svc-scan nmap -n -sT -p 111 198.51.100.1
… Nmap scan report for 198.51.100.1 … PORT STATE SERVICE 111/tcp open rpcbind …

Stop the socket as well, then mask both units so that nothing can start them again:

deploy@web01 · Ubuntu 26.04 LTS
$ sudo systemctl disable --now rpcbind.socket
$ sudo systemctl mask rpcbind.service rpcbind.socket
Created symlink '/etc/systemd/system/rpcbind.service' → '/dev/null'. Created symlink '/etc/systemd/system/rpcbind.socket' → '/dev/null'.
$ sudo ss -tulpn sport = :111
Netid State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
$ sudo systemctl start rpcbind
Failed to start rpcbind.service: Unit rpcbind.service is masked.
$ sudo ip netns exec hard-svc-scan nmap -n -sT -p 111 198.51.100.1
… PORT STATE SERVICE 111/tcp closed rpcbind …

disable --now on the socket prints nothing because its links were already gone, but it stops the socket. Masking both units makes the decision stick; the failed start and the closed port seen from outside are your verification. The impact is that anything needing rpcbind, such as an NFS version 3 mount, now fails until you unmask it. The rollback is unmask and enable --now on the socket:

deploy@web01 · Ubuntu 26.04 LTS
$ sudo systemctl unmask rpcbind.service rpcbind.socket sudo systemctl enable --now rpcbind.socket
Removed '/etc/systemd/system/rpcbind.service'. Removed '/etc/systemd/system/rpcbind.socket'. Created symlink '/etc/systemd/system/sockets.target.wants/rpcbind.socket' → '/usr/lib/systemd/system/rpcbind.socket'.
$ sudo ss -tlpn sport = :111
State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess LISTEN 0 4096 0.0.0.0:111 0.0.0.0:* users:(("systemd",pid=1,fd=79)) LISTEN 0 4096 [::]:111 [::]:* users:(("systemd",pid=1,fd=86))

If nothing on the server needs it, purge the package. Reinstalling it is the rollback, but the configuration a purge deletes does not come back.

deploy@web01 · Ubuntu 26.04 LTS
$ sudo apt-get purge -y rpcbind
… The following packages will be REMOVED: rpcbind* 0 upgraded, 0 newly installed, 1 to remove and 6 not upgraded. …
$ dpkg -l rpcbind | tail -n 1 sudo ss -tulpn sport = :111
un rpcbind <none> <none> (no description available) Netid State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
Never mask ssh.socket on a remote server
On Ubuntu, ssh.socket owns port 22. Stopping, disabling or masking it cuts off new SSH connections, including your next attempt to fix the mistake. The same applies to sshd.service on RHEL.

Packages: less code on disk

deploy@web01 · Ubuntu 26.04 LTS (default install)
$ dpkg-query -W | wc -l apt-mark showmanual | wc -l
682 42
$ dpkg -l telnet inetutils-telnet ftp tnftp | tail -n 4
ii ftp 20260211-1 all dummy transitional package for tnftp ii inetutils-telnet 2:2.7-2ubuntu1.1 arm64 telnet client ii telnet 0.17+2.7-2ubuntu1.1 all transitional dummy package for inetutils-telnet default switch ii tnftp 20260211-1 arm64 enhanced ftp client

A default install has 682 packages, 42 of them marked as installed by hand (apt-mark showmanual); the rest came in as dependencies. The telnet and FTP clients are there by default. They are clients, not listeners, so they add no open port, but they send credentials in clear text, and the CIS RHEL 10 profile requires them removed. The telnet client goes cleanly:

deploy@web01 · Ubuntu 26.04 LTS
$ sudo apt-get purge -y telnet inetutils-telnet
… The following packages will be REMOVED: inetutils-telnet* telnet* 0 upgraded, 0 newly installed, 2 to remove and 6 not upgraded. …
$ apt-get -s purge ftp tnftp | grep -E '^(Inst|Purg)'
Inst ftp-ssl (0.17.34+really0.17-3 Ubuntu:26.04/resolute [arm64]) Purg ftp [20260211-1] Purg tnftp [20260211-1]
$ apt-cache depends ubuntu-standard | grep -A2 'Depends: ftp'
Depends: ftp ftp-ssl tnftp

The FTP client does not. Ubuntu's ubuntu-standard metapackage depends on ftp or ftp-ssl, so the simulation (-s) shows apt installing ftp-ssl to keep that dependency satisfied. Removing ubuntu-standard itself has a wider effect:

deploy@web01 · Ubuntu 26.04 LTS (default install)
$ apt-get -s purge ftp tnftp ubuntu-standard
… The following packages were automatically installed and are no longer required: busybox-static command-not-found dmidecode friendly-recovery hdparm ibverbs-providers inetutils-telnet info install-info iputils-tracepath libevdev2 libibverbs1 libncurses6 libnl-3-200 libnl-route-3-200 libpcap0.8t64 libplymouth5 libsensors-config libsensors5 libtraceevent1-plugin libtracefs1 libxkbcommon0 mtr-tiny nano numactl plymouth plymouth-theme-ubuntu-text python3-commandnotfound rsync sysstat tcpdump telnet time trace-cmd usbutils Use 'apt autoremove' to remove them. …

Everything the metapackage pulled in becomes "no longer required", and the next apt autoremove would take nano, rsync, tcpdump and sysstat with it. SecOpsLog advice: keep ubuntu-standard and accept the FTP client, or remove the metapackage and mark the tools you use as manual (apt-mark manual) first. Listeners are the higher priority either way. The rollback for a removal is reinstalling the package.

The best time to minimise is at install time. Recommended packages are installed by default, and they can be large:

deploy@web01 · Ubuntu 26.04 LTS (default install)
$ apt-get -s install aide | grep '^Inst'
Inst libnsl2 (1.3.0-3build4 Ubuntu:26.04/resolute [arm64]) Inst postfix (3.10.6-4ubuntu2.1 Ubuntu:26.04/resolute-updates, Ubuntu:26.04/resolute-security [arm64]) Inst aide (0.19.2-3 Ubuntu:26.04/resolute [arm64]) Inst liblockfile-bin (1.17-2build2 Ubuntu:26.04/resolute [arm64]) Inst liblockfile1 (1.17-2build2 Ubuntu:26.04/resolute [arm64]) Inst aide-common (0.19.2-3 Ubuntu:26.04/resolute [all]) Inst bsd-mailx (8.1.2-0.20220412cvs-1.1build1 Ubuntu:26.04/resolute [arm64]) Inst ssl-cert (1.1.3ubuntu2 Ubuntu:26.04/resolute [all])
$ apt-get -s install --no-install-recommends aide | grep '^Inst'
Inst aide (0.19.2-3 Ubuntu:26.04/resolute [arm64])

aide alone is one package; with its recommendations it brings a mail server, postfix. Use --no-install-recommends when you install server software, and add the recommended packages you actually want by name.

Bind to loopback, then check from outside

Some services must run but only need to be reached from the machine itself. The lab's example is a small internal status page: Python's built-in web server, which by default binds to all interfaces (the Python documentation says so), serving /srv/hard-svc-app/index.html (one line, "internal status page") from this unit. Write it, then run sudo systemctl daemon-reload and sudo systemctl start hard-svc-app.

/etc/systemd/system/hard-svc-app.service
[Unit]
Description=Internal status page (demo)
[Service]
Type=exec
DynamicUser=yes
ExecStart=/usr/bin/python3 -m http.server 8080 --directory /srv/hard-svc-app
[Install]
WantedBy=multi-user.target

Then scan all ports from the other machine:

deploy@web01 · Ubuntu 26.04 LTS
$ sudo ss -tlpn sport = :8080
State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess LISTEN 0 5 0.0.0.0:8080 0.0.0.0:* users:(("python3",pid=278007,fd=3))
$ sudo ip netns exec hard-svc-scan nmap -n -sT -p- 198.51.100.1
… Nmap scan report for 198.51.100.1 … Not shown: 65533 closed tcp ports (conn-refused) PORT STATE SERVICE 22/tcp open ssh 8080/tcp open http-proxy MAC Address: DA:B3:E3:C8:2E:07 (Unknown) …

-p- means all 65,535 TCP ports. Anyone on this network can read the status page on 8080. Rebind it with a drop-in:

deploy@web01 · Ubuntu 26.04 LTS
$ printf "[Service]\nExecStart=\nExecStart=/usr/bin/python3 -m http.server 8080 --bind 127.0.0.1 --directory /srv/hard-svc-app\n" | sudo systemctl edit --stdin hard-svc-app sudo systemctl restart hard-svc-app
Successfully installed edited file '/etc/systemd/system/hard-svc-app.service.d/override.conf'.
$ ss -tln sport = :8080 curl -s http://127.0.0.1:8080/
State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 5 127.0.0.1:8080 0.0.0.0:* internal status page
$ sudo ip netns exec hard-svc-scan nmap -n -sT -p- 198.51.100.1
… Nmap scan report for 198.51.100.1 … Not shown: 65534 closed tcp ports (conn-refused) PORT STATE SERVICE 22/tcp open ssh MAC Address: DA:B3:E3:C8:2E:07 (Unknown) …

The socket is now on 127.0.0.1, the page still works locally, and the scan finds only SSH. The rule is SecOpsLog advice: bind every internal service to loopback even though a firewall comes later in this course. The two are independent, so an internal service stays unreachable on the day the firewall is flushed. The impact is that remote clients, including a monitoring server, can no longer connect directly. To roll back, run sudo systemctl revert hard-svc-app and restart it.

On RHEL 10

deploy@rocky10 · Rocky Linux 10.2
$ sudo ss -tulpn
Netid State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess udp UNCONN 0 0 127.0.0.1:323 0.0.0.0:* users:(("chronyd",pid=757,fd=4)) udp UNCONN 0 0 [::1]:323 [::]:* users:(("chronyd",pid=757,fd=5)) tcp LISTEN 0 4096 127.0.0.1:33035 0.0.0.0:* users:(("containerd",pid=1216,fd=15)) tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=961,fd=7)) tcp LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=961,fd=8)) tcp LISTEN 0 4096 *:9090 *:* users:(("systemd",pid=1,fd=205))
$ systemctl list-unit-files cockpit.socket cockpit.service
UNIT FILE STATE PRESET cockpit.service static - cockpit.socket enabled enabled 2 unit files listed.
$ grep -r cockpit /usr/lib/systemd/system-preset/
/usr/lib/systemd/system-preset/90-default.preset:enable cockpit.socket

The Rocky Linux machine runs sshd.service directly on port 22. The containerd line belongs to the lab VM tool's own user and listens on loopback only. Port 9090 is the Cockpit web console, socket-activated. Rocky's release package enables cockpit.socket through its systemd preset file, so the console answers on every address until you decide otherwise. Check your RHEL image the same way: the preset column tells you what the distribution chose. The CIS RHEL 10 Level 2 server profile disables it.

deploy@rocky10 · Rocky Linux 10.2
$ sudo systemctl disable --now cockpit.socket sudo ss -tlnp sport = :9090
Removed '/etc/systemd/system/sockets.target.wants/cockpit.socket'. State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
$ sudo systemctl enable --now cockpit.socket
Created symlink '/etc/systemd/system/sockets.target.wants/cockpit.socket' → '/usr/lib/systemd/system/cockpit.socket'.

Package work uses dnf: dnf repoquery --userinstalled lists what was installed on purpose (50 packages on this machine), dnf remove removes, and --setopt=install_weak_deps=False is the counterpart of --no-install-recommends.

Try this

On your Ubuntu lab machine, install rpcbind and run sudo systemctl disable --now rpcbind. Confirm with sudo ss -tulpn sport = :111 that port 111 is still open and that systemd is its only owner. Close it for good (stop the socket, mask both units) and confirm that sudo systemctl start rpcbind fails with "Unit rpcbind.service is masked." Then roll back with unmask and enable --now rpcbind.socket, check that 111 is back, and finish with sudo apt-get purge rpcbind. At the first and second stage, scan port 111 from your laptop with nmap -n -sT -p 111 SERVER: open, then closed.

Takeaway

Every open port needs an owner and a reason. Close socket-activated services at their .socket unit, bind internal services to 127.0.0.1, and prove the result from another machine rather than from the configuration file.

Quick check
01On a RHEL 10 server you run sudo systemctl stop cockpit.service, but a scan from another host still finds port 9090 open, and ss shows only systemd (pid 1) on it. What is going on?
Incorrect — A connect scan opens a real connection each time; ss on the server confirms the socket is really listening.
Incorrect — A firewall only filters traffic to a listening socket. It never creates a listener, and ss shows one owned by systemd.
Correct — The console is socket-activated: stopping the service leaves the socket unit holding the port. Stop and disable, or mask, cockpit.socket.
Incorrect — stop acts immediately on the unit named. The port stays open because a different unit, the socket, owns it.
02You disabled and stopped both rpcbind.service and rpcbind.socket. A month later port 111 is open again after a colleague installed an NFS client that depends on rpcbind. Which step would have kept it closed?
Correct — A masked unit is linked to /dev/null and cannot be started by anything; the install would have reported it instead of silently starting it.
Incorrect — daemon-reload re-reads unit files; it does not stop a unit from being started later.
Incorrect — disable is already persistent, but it only removes boot links. Package scripts and dependencies can still start a disabled unit.
Incorrect — A firewall filters packets; it does not prevent systemd or a package from starting rpcbind and opening the socket.
03An internal metrics endpoint listens on 0.0.0.0:9100 and only a local agent reads it. A colleague proposes a firewall rule instead of changing the bind address. What does binding it to 127.0.0.1 give you that the firewall rule alone does not?
Incorrect — Loopback traffic is not encrypted. It simply never leaves the machine.
Incorrect — ss shows loopback listeners too, as the 127.0.0.1:8080 line in the lesson did.
Incorrect — Firewalls filter any port. The rule would work while it is in place.
Correct — With no socket on a routable address there is nothing to connect to, whatever the firewall state. The two controls fail independently.

Related