skip to content

When an IPv4 router forwards a datagram, which header fields does it change, and why must it update the header checksum at every hop?

level: middleimportance: should knowfreq 35%

answer

  1. one byte always moves
  2. the checksum guards the header only
  3. 16-bit one's complement sum
  4. addresses ride through untouched
  5. adjust rather than re-sum

basics

~20 s

An IPv4 router always decrements TTL, and because the Header Checksum covers the whole header, it must update the checksum too. A plain forwarding hop leaves addresses, Protocol and Identification alone; fragmenting, option processing or DSCP/ECN marking change more.

solid answer

~50 s

Every forwarding router decrements `Time to Live`, and the `Header Checksum` — the 16-bit one's complement of the one's complement sum of the header's 16-bit words — covers the header only, TTL included. So RFC 791 says it is recomputed and verified wherever the header is processed: RFC 1812 makes the router verify it on arrival and silently discard a bad datagram, then write a new value after the decrement, and allows an incremental update when TTL is the only change. A plain hop leaves the addresses, `Protocol`, `Identification` and `Total Length` alone. Other fields move only for a reason: fragmenting rewrites the length and fragment fields, record-route and timestamp options get filled in, a boundary may re-mark DSCP, a congested router may set ECN's CE. Rewriting addresses is a NAT's job, not forwarding. The payload is left to transport checksums, which is why a header-only checksum is cheap enough to redo per hop.

code

pseudocode · 16 lines
pseudocode
function ones_sum(words):              // 16-bit words of the header
    s = 0
    for w in words:
        s = s + w
        s = (s & 0xFFFF) + (s >> 16)     // end-around carry
    return s

function forward(hdr):                   // unicast, not addressed to this router
    if ones_sum(hdr.words) != 0xFFFF:
        discard silently; return
    if hdr.ttl <= 1:
        discard; send ICMP Time Exceeded (type 11, code 0) to hdr.source; return
    hdr.ttl = hdr.ttl - 1                 // TTL/Protocol word fell by 0x0100
    c = hdr.checksum + 0x0100             // so the checksum rises by 0x0100
    hdr.checksum = (c & 0xFFFF) + (c >> 16)
    send hdr toward the next hop for hdr.destination

go deeper

for a junior

Recall that every router decrements TTL and must therefore rewrite the header checksum, and that the source and destination addresses stay the same across a plain router.

for a middle

Explain the one's complement checksum over the header only, which other fields move and why, and that a bad checksum means a silent discard with no override.

for a senior

Separate forwarding from translation and marking when reading a capture taken on both sides of a hop, and explain why RFC 1812 prefers adjusting the checksum to recomputing it.

for a principal

Discuss the cost of per-hop header integrity at line rate and why IPv6 removed the header checksum, trading it for transport and link checks.

## The checksum, exactly RFC 791 defines the `Header Checksum` as "the 16 bit one's complement of the one's complement sum of all 16 bit words in the header", computed with the checksum field itself set to zero. In steps: 1. Treat the header (20 bytes, or up to 60 with options) as a sequence of 16-bit words. 2. Add them, folding any carry out of the top bit back into the bottom (**end-around carry**). 3. Invert the result; that is the checksum. 4. To verify, sum every word *including* the checksum: an intact header sums to all ones, `0xFFFF`. The key phrase in RFC 791 is **"a checksum on the header only"**. It covers no payload byte. ## What changes at a hop, and what does not On a plain forwarding hop — no fragmentation, no options, no re-marking — exactly two fields change: `Time to Live` goes down by at least one, and therefore `Header Checksum` is rewritten. Everything else can change only for a specific reason: | Field | Plain forwarding hop | When it does change | |---|---|---| | `Time to Live` | decremented, always | — | | `Header Checksum` | rewritten, always | — | | `Version`, `Protocol` | unchanged | never in forwarding | | `Source Address` | unchanged | a NAT rewrites it; that is translation, not routing | | `Destination Address` | unchanged | a source-route option supplies the next listed address; a NAT may rewrite it | | `Identification` | unchanged | copied into every fragment when the router fragments | | `Total Length`, `MF`, `Fragment Offset` | unchanged | rewritten per fragment when the router fragments | | `DSCP` | unchanged | re-marked at an administrative boundary | | `ECN` | unchanged | set to CE by a congested ECN-capable router | | `Options` | unchanged | record-route and timestamp data filled in | Any of those changes alters header bytes, so each one also requires a checksum update. ## Why the checksum covers the header only The design is deliberate and has three consequences: - **It is cheap enough to redo at every hop.** A 20-byte header is ten 16-bit words; a checksum over a 1,500-byte payload would be seventy-five times the work, at every router, for data the router never reads. - **The payload is someone else's job.** TCP and UDP carry their own checksums over their header and data, plus a pseudo-header of IP addresses; link layers add their own per-hop error checks. The IP checksum only has to keep a router from acting on a corrupted header — a mangled destination, length or TTL. - **IPv6 went further and dropped it.** The IPv6 header defined in RFC 8200 has no checksum field at all, so routers there have nothing to recompute. ## What a router must do with a bad checksum RFC 1812 section 5.2.2 lists the checks a router runs before processing any IPv4 packet: enough bytes for a 20-byte header, **a correct checksum**, version 4, an `IHL` of at least 5, a `Total Length` at least as large as the header. A packet that fails **MUST be silently discarded**, and the router **MUST NOT** offer a setting that disables these tests. Hosts are under the same rule: RFC 1122 requires a host to verify the checksum on every datagram and silently discard bad ones. ## Incremental update RFC 1812 section 4.2.2.5 says a router **MAY update the checksum incrementally** when TTL is the only change, and gives the reason: it "will reduce the possibility of undetected corruption of the IP header by the router." The arithmetic is small. TTL is the high byte of the 16-bit word it shares with `Protocol`, so decrementing TTL by one lowers that word by `0x0100`. Because the checksum is the complement of the sum, it rises by `0x0100`, with end-around carry. Why is adjusting safer than re-summing? A full recomputation sums whatever bytes the router now holds. If a fault inside the router corrupted a field, a fresh checksum would bless the corruption and the next hop would accept it. Adjusting the old checksum only for the TTL change carries the sender's error detection forward, so damage done inside the router still fails at the next hop. ## The summary to give in an interview - Every hop: TTL down, checksum rewritten. - Header only: the checksum never covers payload. - Never on a plain hop: addresses, Protocol, Identification, Total Length. - Bad checksum: silent discard, no override. - IPv6: no header checksum to maintain.

  • Why does RFC 1812 say an incremental IPv4 checksum update reduces undetected header corruption?
    A full recomputation sums whatever bytes the router now holds, so if a fault inside the router corrupted a field, the fresh checksum would make the corruption look valid downstream. Adjusting the received checksum only for the TTL change keeps the sender's protection over every other field, so damage done inside the router still fails verification at the next hop.
  • If the IPv4 header checksum covers only the header, what protects the payload?
    The transport and the links. TCP and UDP checksums cover their own header and data plus a pseudo-header with the IP addresses and protocol (UDP's is optional over IPv4), and each link layer checks its frames hop by hop. IPv6 leans on the same pair and has no header checksum at all.

saying these in an interview costs you the question

  • The IPv4 header checksum covers the payload as well as the header.
  • The sender computes the checksum once and it stays the same end to end.
  • Routers write their own address into the source field as they forward.
  • A router that finds a bad header checksum recomputes it and forwards anyway.
  • IPv6 kept the header checksum but made it optional.