Quick answer
GRE (Generic Routing Encapsulation) is a tunneling protocol that wraps one packet inside another so it can travel across an intermediate network as if the two endpoints were directly connected. In DDoS protection it is used to deliver filtered traffic: attack traffic is scrubbed on the provider's network, and what survives is encapsulated and handed to your server through the tunnel — which means your server's real address never has to appear in public routing.
01How encapsulation works
A normal packet has one IP header saying where it came from and where it is going. GRE adds an outer header around the whole original packet, so the original becomes payload.
The outer header addresses the tunnel endpoints — the provider's router and yours. Routers in between only see that outer header and forward it like any other traffic, with no knowledge of what is inside. When it reaches your end, the outer header is stripped and the original packet is processed as if it had arrived directly.
GRE is specified in RFC 2784. Its base header is 4 bytes, and the whole packet travels as IP protocol 47 rather than TCP or UDP, which is why firewalls need a rule for protocol 47, not for a port number. The result is a virtual point-to-point link between two networks that may be far apart, without either party needing a physical circuit to the other.
┌─────────────── outer IP header ───────────────┐
│ src: provider edge dst: your tunnel endpoint │
│ ┌────────────── GRE header ──────────────┐ │
│ │ ┌────────── original packet ────────┐ │ │
│ │ │ src: visitor dst: your service │ │ │
│ │ └───────────────────────────────────┘ │ │
│ └────────────────────────────────────────┘ │
└───────────────────────────────────────────────┘02Why DDoS protection uses it
Protecting a non-HTTP service means getting its traffic to a filtering network first, and a web proxy cannot carry it, as Layer 3/4 vs Layer 7 protection explains. DNS cannot do it either — a DNS record points a name at an address, but the packets still go wherever that address routes. GRE solves the delivery problem: the provider advertises the protected addresses, so all traffic for them arrives at the scrubbing network first.
Once filtered, the clean traffic has to reach your actual machine, which is somewhere else entirely and has a different address. The tunnel carries it there. From your server's point of view the packets arrive with their original source addresses intact, so logging, geolocation and application logic all keep working normally.
- Works for any protocol, including UDP, which no HTTP proxy can handle
- Your hardware stays where it is — no migration required
- Original client addresses are preserved, so your logs stay meaningful
- The origin address is not published, so attackers have nothing to aim at directly
03Return traffic: through the tunnel or direct
Inbound traffic always arrives through the provider. Replies can take one of two routes, and the choice affects latency, MTU and what your own upstream must allow.
| Symmetric: replies through the tunnel | Direct return: replies via your uplink | |
|---|---|---|
| Reply path | Back to the provider, then out | Straight from your server to the visitor |
| Latency | Adds the trip to the provider | Shortest path |
| You need | Policy routing so replies use the tunnel | An upstream that accepts the protected source addresses, and loose reverse-path filtering |
| Packet size | Both directions limited by the tunnel | Only inbound limited by the tunnel |
| Usual fit | Provider-assigned addresses | Your own prefix with a cooperative upstream |
04Your own addresses, or the provider's
There are two ways to run this. With BYOIP (bring your own IP), you own an address range, in practice at least a /24 because longer prefixes are generally filtered, and authorise the provider to announce it on your behalf. Your addresses stay yours, which matters if they are baked into client configurations, allowlists or DNS you do not control. It also needs a ROA that authorises the announcing network, or networks that validate routes may reject it; what RPKI is explains how.
Alternatively the provider assigns you addresses from their own range. This is faster to set up and requires no address ownership, but the addresses are not portable — if you leave, you renumber.
05MTU, MSS and encryption
GRE adds 24 bytes to every packet on an IPv4 path: 20 for the outer IPv4 header and 4 for the GRE header. Each optional field, such as the key from RFC 2890, adds 4 more, and an IPv6 outer header makes the base overhead 44. If that is not accounted for, full-size packets fragment or are dropped, and the classic symptom is that small requests work while large uploads or TLS handshakes hang. RFC 4459 explains why path MTU discovery cannot be relied on to fix it over IPv4: firewalls and other middleboxes are often configured to drop the ICMP messages it depends on.
Set the tunnel MTU and clamp the TCP maximum segment size (MSS) on SYN packets, so connections never attempt segments that do not fit. The full arithmetic, including IPv6 inside the tunnel and the Linux commands, is in GRE vs IPIP, and the MTU and MSS calculator works the numbers out for stacked tunnels such as GRE over PPPoE.
GRE also provides no encryption or authentication of its own; it is a delivery mechanism, not a security protocol. That is rarely a problem here, because the payload is ordinary internet traffic that was never private in the first place, but it is worth being explicit about; where the link itself must be private, GRE is paired with IPsec.
| Tunnel | Overhead | Tunnel MTU on a 1,500-byte path | TCP MSS, IPv4 inside |
|---|---|---|---|
| GRE over IPv4 | 24 bytes | 1,476 | 1,436 |
| GRE over IPv4 with a key | 28 bytes | 1,472 | 1,432 |
| GRE over IPv6 | 44 bytes | 1,456 | 1,416 |
06Checking a GRE tunnel
Three checks confirm a tunnel passes traffic and is sized correctly. In the example, 203.0.113.1 is the provider's tunnel endpoint and 10.10.10.1 the far end of the tunnel's own /30 link; a subnet calculator helps when planning those small point-to-point ranges.
# GRE packets from the provider's endpoint arriving on the physical interface
tcpdump -nni eth0 'ip proto 47 and src host 203.0.113.1'
# tunnel counters: RX should rise while traffic flows, errors should not
ip -s link show dev gre1
# largest unfragmented ping through a 1,476-byte tunnel: 1,476 - 28 = 1,448
ping -M do -s 1448 -c 3 10.10.10.1
# one byte more must fail locally with: message too long, mtu=1476
ping -M do -s 1449 -c 1 10.10.10.107Before you put a service behind a GRE tunnel
- Allow GRE (protocol 47) only from the provider's tunnel endpoints, and the service ports only through the tunnel
- Set the tunnel MTU and MSS clamping on day one, not after the first stalled upload
- Decide the return path and test it from an outside network
- If you bring your own prefix, publish the ROA before the first announcement
- Monitor the far tunnel address: RFC 2784 defines no keepalive, so a dead tunnel can still look up
- Remove old DNS records and banners that expose the real address
Questions
Frequently asked questions
Sources
Sources and verification
Tunnel checks run over a real GRE tunnel between two isolated network namespaces joined by a veth pair (iproute2 6.1.0, MTU 1476): a 1,448-byte ping with DF set passed, 1,449 bytes failed locally with "message too long, mtu=1476", and the tcpdump 4.99.3 filter captured GRE from the far endpoint. Debian 12, October 2026. MTU figures follow from the header sizes in RFC 2784 and RFC 2890.
- 01RFC 2784: Generic Routing Encapsulation (GRE) · IETF
- 02RFC 2890: Key and Sequence Number Extensions to GRE · IETF
- 03RFC 4459: MTU and Fragmentation Issues with In-the-Network Tunneling · IETF
- 04RFC 2827 (BCP 38): Network Ingress Filtering · IETF
- 05ip-link(8): GRE, IPIP and SIT tunnel options · man7.org
Last updated