Home / Alt manpages / services(5)

  • services(5)
  • File format
  • linux

Read and Safely Edit /etc/services on Linux

An app throws "connection refused" on a port you swear should be open, and half the time the answer is sitting in /etc/services, not the firewall. You will finish with a reliable way to look up service names and ports, add one local mapping without damaging the system file, and check what the resolver actually returns. This follows the installed Linux man-pages 6.7 documentation and uses getent, already present on this machine.

Allow about ten minutes. You need a shell and read access to /etc/services. Reading and checking entries is unprivileged. Editing the file needs root, changes name-to-port data for local programs, and should happen in a maintenance window if applications depend on the mapping. An entry in this file does not start a daemon, open a firewall port or prove anything is listening.

1. Check which file and package you have

The conventional path is /etc/services. The library constant _PATH_SERVICES, declared through <netdb.h>, defines the path programs actually use, so do not assume a hand-made copy elsewhere is what gets read.

Confirm the local package version and file path with ordinary, read-only commands:

$ dpkg-query -W -f='${Package} ${Version}\n' manpages
manpages 6.7-2
$ ls -l /etc/services
-rw-r--r-- 1 root root ... /etc/services

The date and size fields can differ. What matters is that the file exists and is normally owned by root. On a non-Debian system the package query may not exist; that does not change the file format below.

2. Look up a name before reading the whole file

Use getent services for the system's actual name-service lookup rather than a text search. It asks the C library service database for the answer applications are likely to get:

$ getent services ssh
ssh                   22/tcp
$ getent services http/tcp
http                  80/tcp www

The output is a service name, a decimal port with a slash and protocol, then optional aliases. A lookup can return nothing when a name is absent. Query the port as well as the name when diagnosing a configuration:

$ getent services 22/tcp
ssh                   22/tcp

Checkpoint

A returned entry proves the service database can resolve the name. It does not prove a process is listening. Use a separate tool such as ss for that; treat it as a different question entirely.

3. Read the file's line format

Each active line has this shape:

service-name    port/protocol    alias1 alias2    # optional comment
  • Spaces or tabs separate the fields. The service name must start in the first column, is case sensitive, and should stick to lowercase letters, digits and hyphens.
  • The protocol should match one the system knows, commonly tcp or udp.
  • Blank lines are ignored and a hash starts a comment running to end of line.

Many assigned services have separate TCP and UDP entries. Do not merge them just because the port number matches; these are distinct mappings:

example-dns     5353/tcp
example-dns     5353/udp

Keep one protocol per line. A line that does not match the format may be silently skipped by the lookup routines on this system, but that is not a safe validation strategy.

4. Make a reversible backup before editing

Editing /etc/services is a privileged operation. Before changing it, preserve the current file and its metadata. Use sudo only if your account is authorised to administer the machine:

$ sudo cp --preserve=all /etc/services /etc/services.bak
$ sudo ls -l /etc/services /etc/services.bak

That backup is a recovery point, not a permanent archive: do not overwrite it repeatedly while experimenting. If the edit goes wrong, restore it explicitly and verify the lookup again:

$ sudo cp --preserve=all /etc/services.bak /etc/services
$ getent services example-internal

Warning

Restoring the backup discards later edits to this file. Confirm it is the backup you actually intend to use before running the command.

5. Add a local mapping with a temporary file

Choose a name that will not be confused with an IANA-assigned service, and a port and protocol that match the application you are configuring. The example below adds a private TCP mapping on port 18080. It does not bind the port or launch anything.

First inspect the target line without changing the file:

$ grep -nE '^[[:space:]]*example-internal([[:space:]]|$)' /etc/services || true

If nothing prints, create a temporary copy, append the entry, inspect it, then install it with root ownership and mode. The temporary file stays in /tmp until the final command succeeds:

$ tmp_services=$(mktemp)
$ cp --preserve=all /etc/services "$tmp_services"
$ printf '%s\n' 'example-internal 18080/tcp # local application' >> "$tmp_services"
$ tail -n 3 "$tmp_services"
$ sudo install --owner=root --group=root --mode=0644 "$tmp_services" /etc/services
$ rm "$tmp_services"
$ getent services example-internal
example-internal      18080/tcp

Check the output before installing. The temporary file holds a copy of the whole database, so a typo in the appended line is easier to spot there than after a direct edit. The final rm only removes the temporary file, not the recovery backup.

6. Diagnose a missing or misleading result

If getent services example-internal prints nothing, check the spelling, first-column position and exact protocol; names are case sensitive. Also inspect the file directly:

$ grep -nF 'example-internal' /etc/services
$ getent services 18080/tcp

If the file has the line but getent will not return it, check the host's name-service configuration and the line's syntax before editing again. Do not add spaces before the service name, swap a comma in for the slash, or drop a comment into the middle of the port and protocol field.

To tell this database apart from a live network service, check listeners separately:

$ ss -ltn '( sport = :18080 )'
State  Recv-Q Send-Q Local Address:Port Peer Address:Port

An empty result is expected if nothing has bound port 18080. The /etc/services entry still lets programs translate the name to that port. Ports below 1024 are normally restricted to root when a process binds them, but a text entry here does not grant that privilege and does not bypass firewall policy.

Done means

  • getent services NAME returns the expected port and protocol.
  • The entry uses the right shape: first-column name, decimal port, slash, valid protocol, optional aliases or comment.
  • TCP and UDP mappings are separate when both are required.
  • The file was backed up before the privileged edit, and the backup can restore the previous state.
  • You checked the lookup separately from whether anything is actually listening or a firewall permits traffic.