Transport Layer & Port Numbers How TCP/UDP Identify Applications

 

Chapter 58 – Part 3: Transport Layer & Port Numbers
How TCP/UDP Identify Applications — Well-Known, Registered & Ephemeral Ports
Topic
Port Numbers
Level
Beginner to Intermediate
Part
3 of 5

The Transport Layer’s Job

The transport layer provides end-to-end communication between applications on different hosts. The IP layer gets a packet to the right machine, but how does the operating system know which application on that machine should receive the packet? That is solved by port numbers.

A port number is a 16-bit unsigned integer (range: 0 to 65535). Combined with an IP address, it forms a socket address that uniquely identifies one endpoint of a network connection. Both TCP and UDP use port numbers for this purpose.

Key Terms:

Port Number 16-bit Well-Known Ports Registered Ports Ephemeral Ports IANA Privileged Ports CAP_NET_BIND_SERVICE bind() /proc/sys/net/ipv4/ip_local_port_range

1. Categories of Port Numbers

Port numbers are divided into three ranges, each managed differently:

Category Range Assigned By Description
Well-Known Ports 0 – 1023 IANA (strict) Permanently assigned to standard services. Require an approved RFC. Privileged on Linux (root needed).
Registered Ports 1024 – 41951 IANA (less strict) Allocated to developers on a less stringent basis. Availability is not guaranteed for registered purpose.
Dynamic / Private 49152 – 65535 Local use Intended for ephemeral (short-lived) ports assigned by OS to client sockets automatically.

0-1023
1024 – 41951 (Registered)
49152 – 65535 (Ephemeral)
Well-Known (0–1023)   Registered (1024–41951)   Dynamic/Private (49152–65535)

2. Well-Known Ports — Examples

Well-known ports are permanently reserved for specific standard services. Here are some important examples:

Service Protocol Port Purpose
FTP (data) TCP 20 File Transfer Protocol — data transfer
FTP (control) TCP 21 File Transfer Protocol — commands
SSH TCP 22 Secure Shell — encrypted remote login
Telnet TCP 23 Unencrypted remote terminal
DNS UDP/TCP 53 Domain Name System — name resolution
HTTP TCP 80 HyperText Transfer Protocol — web
HTTPS TCP 443 HTTP over TLS — secure web

Note that the same well-known port number is usually registered under both TCP and UDP even if a service uses only one protocol. This avoids confusion across protocols.

3. Privileged Ports on Linux

On Linux, ports in the range 0 to 1023 are privileged. Only a process with the CAP_NET_BIND_SERVICE capability (traditionally root) can bind to these ports. This is a security measure:

Normal User Process

Tries to bind to port 22 (SSH)

bind() fails with EACCES
Cannot impersonate SSH to steal passwords

vs Root / CAP_NET_BIND_SERVICE

Tries to bind to port 22 (SSH)

bind() succeeds
Legitimate SSH daemon can run

On modern Linux, you can grant just this specific capability to a binary without making it fully root: setcap cap_net_bind_service=+ep /path/to/program

4. Ephemeral Ports — Client-Side Automatic Port Assignment

When a client creates a socket and does not call bind(), the OS automatically assigns a temporary (ephemeral) port number. The client does not care which port it uses — it just needs a port for the server to send replies back.

Client
IP: 192.168.1.100
Port: 54321
(auto-assigned ephemeral)
SYN ──────────────→
← SYN-ACK
ACK ──────────────→
Server
IP: 10.0.0.5
Port: 80
(well-known, manually bound)

The server knows where to reply because the client’s ephemeral port is included in every packet as the source port. On Linux, the range of ephemeral ports is controlled by:

# View current ephemeral port range on Linux
cat /proc/sys/net/ipv4/ip_local_port_range
# Typical output: 32768   60999

# Change the range (temporary, resets on reboot)
echo "1024 65535" > /proc/sys/net/ipv4/ip_local_port_range

Binding to port 0 explicitly also triggers ephemeral port assignment: addr.sin_port = htons(0); — the OS picks a free port automatically.

5. Coding Example – Querying Port Information
#include <stdio.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main() {
    struct servent *svc;

    /*
     * getservbyname() looks up a service by name in /etc/services
     * Returns struct servent with port in network byte order
     */
    svc = getservbyname("ssh", "tcp");
    if (svc != NULL) {
        printf("Service: %-10s  Port: %d  Protocol: %s\n",
               svc->s_name,
               ntohs(svc->s_port),   /* convert to host byte order */
               svc->s_proto);
    }

    svc = getservbyname("http", "tcp");
    if (svc != NULL) {
        printf("Service: %-10s  Port: %d  Protocol: %s\n",
               svc->s_name,
               ntohs(svc->s_port),
               svc->s_proto);
    }

    /*
     * getservbyport() looks up a service by port number
     * Port must be in NETWORK byte order
     */
    svc = getservbyport(htons(443), "tcp");
    if (svc != NULL) {
        printf("Port 443 = Service: %s\n", svc->s_name);
    }

    return 0;
}
/* Output:
   Service: ssh        Port: 22   Protocol: tcp
   Service: http       Port: 80   Protocol: tcp
   Port 443 = Service: https
*/

Finding Your Ephemeral Port After bind(port=0)

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

int main() {
    int fd;
    struct sockaddr_in addr;
    socklen_t addrlen = sizeof(addr);

    fd = socket(AF_INET, SOCK_STREAM, 0);

    memset(&addr, 0, sizeof(addr));
    addr.sin_family      = AF_INET;
    addr.sin_port        = htons(0);          /* 0 = let OS pick */
    addr.sin_addr.s_addr = htonl(INADDR_ANY);

    bind(fd, (struct sockaddr *)&addr, sizeof(addr));

    /*
     * Use getsockname() after bind() to discover which
     * ephemeral port the OS assigned.
     */
    getsockname(fd, (struct sockaddr *)&addr, &addrlen);
    printf("OS assigned ephemeral port: %d\n", ntohs(addr.sin_port));

    close(fd);
    return 0;
}

Interview Questions – Port Numbers
Q1. What is a port number and why is it needed?A port number is a 16-bit number (0–65535) used by the transport layer (TCP/UDP) to identify which application on a host should receive an incoming packet. The IP address gets the packet to the right machine; the port number gets it to the right application (process). Without port numbers, the OS would not know whether an incoming packet is for a web browser, an SSH session, or a database.

Q2. What are the three categories of port numbers and their ranges?Well-known ports (0–1023): Permanently assigned by IANA to standard services like SSH (22), HTTP (80), HTTPS (443). Require an approved RFC for assignment and are privileged on Linux. Registered ports (1024–41951): Allocated by IANA to developers on a less strict basis — not guaranteed to be available. Dynamic/Private ports (49152–65535): Intended for ephemeral (temporary client-side) use, assigned automatically by the OS.

Q3. Why are ports 0–1023 called privileged ports on Linux?On Linux, only processes with the CAP_NET_BIND_SERVICE capability (traditionally superuser/root) can bind to ports 0–1023. This prevents a malicious normal-user program from impersonating a trusted service — for example, a fake SSH server on port 22 that steals passwords when users try to log in. Legitimate system daemons run as root or with specific capabilities.

Q4. What is an ephemeral port and who assigns it?An ephemeral port is a short-lived port number automatically assigned by the OS to a client socket that has not called bind(). The client needs a port so the server knows where to send its replies. The OS picks an unused port from the dynamic range. On Linux, this range is defined in /proc/sys/net/ipv4/ip_local_port_range (typically 32768–60999). You can also trigger this by binding to port 0 explicitly.

Q5. If TCP port 80 and UDP port 80 are different entities, why does IANA assign the same number to a service on both?Although TCP and UDP port 80 are technically distinct (a TCP connection to port 80 and a UDP datagram to port 80 are handled separately), IANA assigns the same number to a service (HTTP) on both protocols to avoid confusion. Even if HTTP only uses TCP, reserving the same UDP port number prevents another service from using UDP 80 and causing ambiguity when people see port 80 in use.

Q6. How can you find the port assigned to a socket after binding to port 0?Use the getsockname() system call after bind(). It fills in the sockaddr_in (or sockaddr_in6) structure with the actual address and port that the OS assigned. Read sin_port and convert with ntohs() to get the port in host byte order.

Q7. What Linux file controls the ephemeral port range and how do you change it?The file /proc/sys/net/ipv4/ip_local_port_range contains two numbers: the low and high end of the ephemeral port range. You can read it with cat and change it with echo "low high" > /proc/sys/net/ipv4/ip_local_port_range. This change is temporary (lost on reboot). For a permanent change, add the setting to /etc/sysctl.conf: net.ipv4.ip_local_port_range = 1024 65535.

Continue Learning

Next: UDP — connectionless, unreliable, and when to prefer it over TCP.

Part 4: UDP → ← Part 2: IPv6

Leave a Reply

Your email address will not be published. Required fields are marked *