Home / Alt manpages / services(5)

  • services(5)
  • File format
  • linux

Read and Safely Edit /etc/services on Linux

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 guide follows the installed Linux man-pages 6.7 documentation and uses the getent command 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 requires root, changes name-to-port data for local programs, and should be done during 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 that 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 used by programs, so do not assume that a hand-made copy elsewhere is being 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 permission line can differ in its date and size fields. The useful checks are 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 described below.

2. Look up a name before reading the whole file

Use getent services for the system's name-service lookup rather than relying only on a text search. It asks the C library service database for the result that applications are likely to use:

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

The output has a service name, a decimal port followed by a slash and protocol, and optional aliases. A lookup may return nothing when a name is absent. Query a port as well as a name when diagnosing a configuration:

$ getent services 22/tcp
ssh                   22/tcp

Checkpoint: if the name lookup returns an entry, you have proved that the service database can resolve it. You have not proved that a process is listening. Use a separate tool such as ss to investigate listeners, and treat that as a different question.

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 use conservative characters such as lowercase letters, digits and hyphens. The protocol should match a protocol known to the system, commonly tcp or udp. Blank lines are ignored and a hash character starts a comment that continues to the end of the line.

Many assigned services have separate TCP and UDP entries. Do not merge them just because the port number is the same. 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 behaviour 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 record its metadata. Run the following with 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

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

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

Restoring the backup discards later edits to this file. Confirm that it is the backup you 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. Use 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 no line is printed, 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 contains a copy of the whole database, so a typo in the appended line is easier to spot there than after a direct edit. The rm removes only the temporary file after installation; it is 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 actual file:

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

If the file contains a line but getent does not return it, investigate the host's name-service configuration and the line's syntax before making another edit. Do not add spaces before the service name, use a comma in place of the slash, or put a comment in the middle of the port and protocol field.

To distinguish this database 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 listener result is expected if no program 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 adding a text entry 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 a first-column name, decimal port, slash, valid protocol and 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 a process is listening or a firewall permits traffic.