What This Chapter Is About
When your program wants to talk to another program over a network, it uses sockets. For internet communication, every connection needs two things: an IP address (which machine?) and a port number (which service on that machine?).
Linux provides a file called /etc/services that maps human-readable service names (like “http” or “ssh”) to port numbers. It also provides two powerful functions โ getaddrinfo() and getnameinfo() โ that convert between names and numeric addresses in a way that works for both IPv4 and IPv6 without you having to care which protocol is used.
Key Terms in This Part
Every service that communicates over the network uses a port number. Instead of memorising port numbers, Linux stores a mapping of service names to port numbers in a plain text file: /etc/services.
Format of /etc/services
Each line in this file looks like this:
# service-name port/protocol [aliases...] [# comment]
ssh 22/tcp
ssh 22/udp
http 80/tcp www # World Wide Web HTTP
https 443/tcp
ntp 123/udp # Network Time Protocol
syslog 514/udp
rsh 514/tcp # Remote Shell
Each line has:
- service-name โ human-readable name (e.g., “ssh”, “http”)
- port/protocol โ the port number followed by the protocol (tcp or udp)
- aliases โ optional alternative names for the service
- # comment โ optional explanation
Visualising the /etc/services Lookup
| You provide | Lookup in /etc/services | You get back |
|---|---|---|
| “http” | โ match service name โ | Port 80, TCP |
| “ntp” | โ match service name โ | Port 123, UDP |
| “ssh” | โ match service name โ | Port 22, TCP & UDP |
Important Rules About Port Assignments
IANA (Internet Assigned Numbers Authority) is the organisation that officially assigns port numbers. Here are some important rules to understand:
| Rule | Explanation | Example |
|---|---|---|
| Both TCP & UDP assigned even if only one used | IANA assigns both port numbers to a service regardless of which protocol it actually uses. | telnet, ssh, HTTP, SMTP use only TCP โ but UDP port is also assigned to them. |
| UDP-only service still gets a TCP port | Same IANA policy applies in reverse. | NTP uses only UDP 123 โ but TCP port 123 is also reserved for NTP. |
| Some services use both TCP and UDP | Both protocol entries in /etc/services are actively used. | DNS and echo use both. |
| Rare: same port number used by different services on TCP vs UDP | This happened before the IANA policy was adopted. | TCP 514 = rsh (remote shell), UDP 514 = syslog daemon. |
Linux provides library functions to look up the /etc/services file programmatically. The classic functions are getservbyname() and getservbyport(). These are older APIs (single-threaded, not reentrant), but useful to understand.
getservbyname() โ Look up a service by name
#include <netdb.h>
#include <stdio.h>
#include <arpa/inet.h>
int main() {
struct servent *se;
/* Look up the "http" service for TCP */
se = getservbyname("http", "tcp");
if (se == NULL) {
fprintf(stderr, "Service not found\n");
return 1;
}
printf("Service name : %s\n", se->s_name);
printf("Port number : %d\n", ntohs(se->s_port)); /* ntohs: network to host byte order */
printf("Protocol : %s\n", se->s_proto);
return 0;
}
Output:
Service name : http
Port number : 80
Protocol : tcp
getservbyport() โ Look up a service by port number
#include <netdb.h>
#include <stdio.h>
#include <arpa/inet.h>
int main() {
struct servent *se;
/* Port 22 in network byte order */
se = getservbyport(htons(22), "tcp");
if (se == NULL) {
fprintf(stderr, "Port not found in /etc/services\n");
return 1;
}
printf("Service name : %s\n", se->s_name);
printf("Port number : %d\n", ntohs(se->s_port));
printf("Protocol : %s\n", se->s_proto);
return 0;
}
Output:
Service name : ssh
Port number : 22
Protocol : tcp
servent structure are stored in network byte order (big-endian). Always use ntohs() to convert them to host byte order before printing or comparing.Old socket programs were written specifically for IPv4. The functions they used (like gethostbyname()) returned only IPv4 addresses. As IPv6 grew, programmers had to rewrite their code to handle IPv6 separately.
The modern solution is to use getaddrinfo() and getnameinfo() โ they handle both IPv4 and IPv6 transparently. Your code doesn’t need to know which protocol is being used.
Old Way vs New Way
| Old (IPv4 only, obsolete) | New (Protocol-Independent) |
|---|---|
| gethostbyname() โ hostname โ IPv4 address | getaddrinfo() โ hostname + service โ list of socket addresses (IPv4 or IPv6) |
| getservbyname() โ service name โ port | getaddrinfo() โ handles service resolution too |
| gethostbyaddr() โ IP address โ hostname | getnameinfo() โ socket address โ hostname + service name |
| getservbyport() โ port โ service name | getnameinfo() โ handles service name too |
Flow Diagram: Old vs New
|
โ |
|
getaddrinfo(), you write your network code once and it works for both IPv4 and IPv6 without any changes. This is called protocol-independent programming.Functions like gethostbyname() use a static internal buffer to store their result. This means if two threads call the function at the same time, they will corrupt each other’s results. Such functions are called non-reentrant.
| Property | Old functions (gethostbyname etc.) | New functions (getaddrinfo etc.) |
|---|---|---|
| Thread Safe (Reentrant)? | โ No โ uses static buffer | โ Yes โ caller provides buffer |
| IPv6 Support? | โ No | โ Yes |
| Returns port + address together? | โ Separate calls needed | โ Yes, combined |
| Status in POSIX | Obsolete | Current standard |
Q1. What is the /etc/services file and what is its purpose?
Answer: /etc/services is a plain text configuration file in Linux that provides a mapping between human-readable service names (like “http”, “ssh”) and their corresponding port numbers and protocols (tcp or udp). It helps programmers and system administrators refer to services by name rather than memorising port numbers. The C library functions getservbyname() and getservbyport() read this file to perform lookups.
Q2. Is /etc/services a port reservation mechanism?
Answer: No. /etc/services is purely a name-to-number mapping reference. Appearing in this file does not guarantee that the port is available. Another process could already be bound to that port. If you try to bind to a port that is already in use, bind() will fail with EADDRINUSE.
Q3. Why does IANA assign both TCP and UDP ports even if only one protocol is used?
Answer: This is IANA policy for consistency and future-proofing. Even if a service currently uses only TCP (like HTTP), the UDP port is reserved under the same number to prevent conflicts. This avoids a situation where someone assigns UDP 80 to a completely different service in the future, which would cause confusion.
Q4. Why is gethostbyname() considered obsolete?
Answer: Two main reasons: (1) It only supports IPv4, not IPv6. (2) It uses a static internal buffer, making it non-reentrant and unsafe in multi-threaded programs. The modern replacement is getaddrinfo(), which is reentrant, supports both IPv4 and IPv6, and combines hostname and service resolution in a single call.
Q5. What is the difference between TCP port 514 and UDP port 514?
Answer: They are assigned to different services โ TCP 514 is used by rsh (remote shell), while UDP 514 is used by the syslog daemon. This is an exception to the normal IANA policy (where both protocols get the same service) and exists because these assignments were made before the current IANA policy was adopted.
Q6. Name two services that use both TCP and UDP on the same port.
Answer: DNS (port 53) and echo (port 7) are examples of services that actively use both TCP and UDP.
Q7. What does “protocol-independent programming” mean in the context of sockets?
Answer: It means writing network code that works transparently with both IPv4 and IPv6 without needing separate code paths. Using getaddrinfo() and getnameinfo() achieves this because they return/accept generic socket address structures that can represent either protocol, letting the OS handle the protocol-specific details.
Continue Learning
Next: Deep dive into getaddrinfo() โ function signature, addrinfo structure, and result list
