Host Security: Disabling Services and TCP Wrappers
What You Will Achieve
- Enumerate listening services with
ss -tulnp - Explain precisely the difference between
systemctl stop/disable/mask - Understand the TCP Wrappers
/etc/hosts.allow→/etc/hosts.denyevaluation order - Grasp the role of super-servers (inetd / xinetd)
- Apply surrounding defenses such as
/etc/nologinand shadow passwords (pwconv)
This is the core of LPIC-1 objective 110.2 "Setting up host security". It rests on two pillars: reducing the attack surface by disabling unneeded services, and restricting where connections may come from.
What Is the Basic Host Security Policy?
The principle is simple: a service that is not running cannot be attacked. First stop what you do not need, then restrict the source for what remains. Do not reverse this priority.
Hardening a host proceeds in this order without gaps.
- Find out what is listening (
ss -tulnp) - Stop and disable unneeded services (
systemctl) - Restrict connection sources for the services you keep (TCP Wrappers / firewall)
- Tighten login and authentication (
/etc/nologin, shadow passwords)
TCP Wrappers (libwrap) is being phased out in newer distributions, and Debian / Ubuntu are moving to drop libwrap support. It is still within the LPIC-1 110.2 objectives, so this article explains how it works.
How Do You Check Which Services Are Listening?
First, make visible what is currently waiting for external connections. ss -tulnp is today's standard command.
ss -tulnp
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
udp UNCONN 0 0 0.0.0.0:68 0.0.0.0:* users:(("dhclient",pid=712,fd=6))
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=901,fd=3))
tcp LISTEN 0 100 127.0.0.1:25 0.0.0.0:* users:(("master",pid=980,fd=13))
The ss options mean the following. -p shows the process name only with root privileges.
| Option | Meaning |
|---|---|
-t |
TCP sockets |
-u |
UDP sockets |
-l |
Listening sockets only |
-n |
Show ports numerically (no resolve) |
-p |
Show the process using the socket |
ss is from the iproute2 package and is the successor to the legacy netstat -tulnp (net-tools). The output reads with nearly the same meaning.
Here 0.0.0.0:Port means listening on all interfaces (reachable externally), while 127.0.0.1:Port means loopback only (not reachable from outside). In the example above, SSH (22) is exposed externally while SMTP (25) is local-only.
What Is the Difference Between stop, disable, and mask?
In short: stop means "stop now", disable means "do not start next boot", and mask means "make it impossible to start". Their roles differ, and you combine them.
Steps to stop and disable an unneeded service
systemctl stop avahi-daemon systemctl disable avahi-daemon
Removed "/etc/systemd/system/multi-user.target.wants/avahi-daemon.service".
stop alone lets the service come back after a reboot. To stop it permanently you need disable. Do both in one line with --now.
systemctl disable --now avahi-daemon
disable --now performs an immediate stop (like stop) and disables autostart (disable) at the same time. This is the form you use most in practice.
Lock a service with mask
systemctl mask avahi-daemon systemctl start avahi-daemon
Created symlink /etc/systemd/system/avahi-daemon.service → /dev/null. Failed to start avahi-daemon.service: Unit avahi-daemon.service is masked.
mask creates a symlink from the unit file to /dev/null and refuses both a manual start and any start triggered by dependencies. It is stronger than disable. Reverse it with unmask.
| Command | Stop now | Autostart | Manual start | Use |
|---|---|---|---|---|
stop |
Yes | Unchanged | Allowed | Stop temporarily |
disable |
No | Off | Allowed | Prevent autostart next time |
disable --now |
Yes | Off | Allowed | Standard form in practice |
mask |
No | Off | Blocked | When it must never start |
Check state with systemctl is-enabled svc (autostart) and systemctl is-active svc (running or not).
A masked service can also fail the startup of other services that depend on it. Use it only for things you truly do not need, and when in doubt stick to disable.
What Are Super-Servers (inetd / xinetd)?
A super-server listens on behalf of several small services and launches the target daemon only when a connection arrives. This reduces the number of resident processes.
Historically there was inetd, with xinetd as its extended version. The configuration structure is as follows.
| File / Directory | Role |
|---|---|
/etc/inetd.conf |
inetd configuration (one line per service) |
/etc/xinetd.conf |
xinetd main configuration and defaults |
/etc/xinetd.d/ |
Directory holding per-service xinetd configuration files |
To stop a service under xinetd, set disable = yes in its definition and reload xinetd.
cat /etc/xinetd.d/telnet
service telnet
{
socket_type = stream
protocol = tcp
wait = no
user = root
server = /usr/sbin/in.telnetd
disable = yes
}
disable = yes turns that service off. The defaults block in /etc/xinetd.conf holds settings common to all services (log format, connection limits, and so on).
Current distributions have systemd socket activation (.socket units) take over xinetd's role. The exam asks about the inetd / xinetd concept and the location of the configuration files.
How Do TCP Wrappers Control Access?
TCP Wrappers control connections to libwrap-linked services on a per-host basis. Two files govern it: /etc/hosts.allow and /etc/hosts.deny.
Evaluation order (most important)
According to the hosts_access(5) manual, the decision is made in the following order, and the first matching rule wins (first match wins).
- Search
/etc/hosts.allowtop to bottom. On a match, grant access and stop. - If no match, search
/etc/hosts.deny. On a match, deny access and stop. - If neither file matches, grant access (default allow).
So allow always takes precedence over deny. For a closed policy, the standard pattern is "deny everything, then open holes with allow".
cat /etc/hosts.deny
ALL: ALL
cat /etc/hosts.allow
sshd: 192.168.1.0/24 sshd: 10.0.0.5 ALL: LOCAL
In this example, hosts.deny first denies all services and all hosts (ALL: ALL). Then hosts.allow permits only 192.168.1.0/24 and 10.0.0.5 to reach sshd, plus local connections to all services. Because allow is evaluated first, the permitted connections pass and everything else falls through to deny.
Format and wildcards
A rule has the form daemon_list : client_list.
| Element | Meaning |
|---|---|
| daemon_list | Service process names (sshd, vsftpd, etc.). ALL for all |
| client_list | Source host / IP / network. ALL for all |
ALL |
Wildcard that always matches |
EXCEPT |
"A EXCEPT B" = matches A but excludes B |
LOCAL |
Host names without a dot (the local host) |
Here is an EXCEPT example.
cat /etc/hosts.allow
sshd: ALL EXCEPT 192.168.1.100
This means "allow sshd connections from every host except 192.168.1.100". Clients can also be specified as .example.com (domain suffix match) or 192.168.1. (network prefix match).
TCP Wrappers only affect services built with libwrap (such as sshd, though it depends on the build configuration) and services under xinetd. It does not stop all traffic, so combine a firewall such as iptables / nftables to block the network as a whole.
Login and Authentication Defenses
After narrowing services, tighten login and authentication too. /etc/nologin and shadow passwords are the representative measures.
Block regular logins with /etc/nologin
When the /etc/nologin file exists, login is refused for regular users (root is exempt). The file's contents become the message shown when login is refused.
echo "System under maintenance. Please try again later." > /etc/nologin
Use it to temporarily block logins during maintenance. Delete the file when work is done and login is restored.
Overview of shadow passwords
Shadow passwords separate the encrypted password from the world-readable /etc/passwd into /etc/shadow, which only root can read. This is enabled by default on current systems.
| Command | Action |
|---|---|
pwconv |
Create /etc/shadow by shadowing /etc/passwd |
pwunconv |
Move /etc/shadow back into /etc/passwd and remove shadow |
grpconv |
Create /etc/gshadow from /etc/group |
grpunconv |
Move /etc/gshadow back into /etc/group and remove gshadow |
pwconv takes passwords out of /etc/passwd and replaces that field with x. pwunconv does the reverse, returning to the non-shadowed layout.
The legacy /etc/inittab defined the default runlevel and the processes started at each level in the SysVinit era. It is unused under systemd, where you manage the target (the runlevel equivalent) with systemctl get-default / set-default. The exam asks you to position inittab as legacy.
Common Mistakes and Fixes
Mistake 1: feeling safe after only stop
systemctl stop only stops the current process. After a reboot, an enabled service comes back. Permanent stop needs disable (or disable --now).
Mistake 2: confusing mask with disable
disable still allows a manual start, but mask refuses even that. If you only wanted a temporary stop yet used mask, you will later be stuck with Unit is masked when trying to start it.
Mistake 3: reversing the hosts.allow and hosts.deny order
Allow first, deny second. Even with ALL: ALL in hosts.deny, connections permitted by hosts.allow still pass. Do not panic when "I closed everything in deny yet a connection got in". The order is correct, expected behavior.
Mistake 4: assuming "closed" with no rules written
If both files are empty or no rule matches, the default is allow. Unless you write an explicit deny rule, TCP Wrappers stops nothing.
Mistake 5: thinking TCP Wrappers affect every service
They affect only libwrap-aware services and those under xinetd. Services that do not use libwrap, such as a web server, ignore hosts.deny. Use a firewall for blanket blocking.
Troubleshooting
Symptom: a disabled service is still running after a reboot
Cause: disable only turns off autostart and does not stop the running process. It may also be started via a socket unit or another service's dependency.
Check:
systemctl is-enabled svc systemctl status svc
Fix: Use systemctl disable --now svc to stop and disable at once. If it is socket-activated, also stop and disable the corresponding svc.socket.
Symptom: a connection is denied even though it is in hosts.allow
Cause: The target service is not libwrap-aware, or the daemon name is misspelled.
Check:
ldd $(which sshd) | grep libwrap
Fix: If libwrap is not linked, TCP Wrappers has no effect; control it at the firewall instead. Match the daemon name exactly to the process name (such as sshd).
Symptom: another service that depends on a masked service fails to start
Cause: mask refuses all starts including dependency resolution, so the dependent service fails in a chain.
Check:
systemctl list-dependencies --reverse svc
Fix: Re-decide whether it is truly unneeded; if there is a dependency, unmask it and switch to disable.
Completion Checklist
- [ ] Enumerated listening services with
ss -tulnp - [ ] Stopped and disabled unneeded services with
disable --now - [ ] Used
maskfor targets that must never start - [ ] Understood the
/etc/hosts.allow→/etc/hosts.denyorder - [ ] Combined a firewall where needed
Summary
| Goal | Command / File | Point |
|---|---|---|
| Check listening | ss -tulnp |
0.0.0.0 means externally exposed |
| Stop now | systemctl stop |
Comes back after reboot |
| Disable for good | systemctl disable --now |
The standard in practice |
| Lock startup | systemctl mask |
Cannot start until unmask |
| Access control | /etc/hosts.allow / .deny |
allow then deny, first match wins |
| Block login | /etc/nologin |
Refuses everyone but root |
Host security rests on two pillars: reducing the attack surface and restricting connection sources. After covering the LPIC-1 110 security area, combine it with encryption and permission management to complete your operational knowledge.
Next Reading
- Security Administration: SUID/SGID and File Permissions
- Data Encryption: SSH and GPG
- systemd and the Boot Process