Address translation is taught as a rewriting exercise and troubleshot as a mystery. The rewriting part is simple: a packet arrives, an address in its header is replaced, an entry is recorded so the reply can be reversed. Everything confusing about it comes from one fact that is rarely stated plainly — translation does not happen at the same point in both directions.
Going out, the router routes first and translates afterwards. Coming in, it translates first and routes afterwards. That asymmetry decides which address an access list sees, which address the routing table is consulted for, and why a configuration that is obviously correct produces a packet that goes somewhere nobody intended. Almost every genuinely puzzling translation problem is a consequence of it.
This article covers what the four address terms mean and why there are four, which flavour of translation to use for what, where translation sits in the packet's journey and what follows from that, what exhausts the translation table, and the failures that look like translation problems and are something else entirely. It is written for the lab rather than for the written exam, and sits alongside the rest of the CCIE Enterprise Infrastructure lab certification track.
What Do the Four Terms Mean?
Why are there four?
Because two hosts can each be seen under two different addresses, and naming them requires saying both which host and from where. The first word names the side the host is on; the second names the side you are looking from. A host on the inside has an inside local address, which is its real one, and an inside global address, which is what the outside sees. A host on the outside has the mirror pair. Most designs use only the inside pair, which is why the other two seem redundant until they are needed.
A Deeper Dive into the Terms
Reading the names
Take them one word at a time. Inside or outside says where the host lives. Local or global says whose view of it this is — local means the inside's view, global means the outside's. So the inside local address is an internal host as the internal network sees it, and the inside global address is the same host as the internet sees it.
Once that decoding is automatic the output of the translation table reads directly, and it stops being a column ordering to memorise.
Why the outside pair exists
To translate the addresses of hosts that are not yours. The case that requires it is overlapping address space: a company merges with another that uses the same private range, so hosts on each side cannot address hosts on the other without something rewriting one of them.
Translating the outside hosts into a range the inside can use gives the inside a set of addresses to aim at that do not collide with its own. It is rare, it is the reason the terms exist, and it is where the order of operations becomes genuinely important.
! The ordinary case: only the inside pair is used
R1# show ip nat translations
Pro Inside global Inside local Outside local Outside global
tcp 203.0.113.5:1024 10.1.1.10:51234 198.51.100.7:443 198.51.100.7:443
tcp 203.0.113.5:1025 10.1.1.11:49876 198.51.100.7:443 198.51.100.7:443
udp 203.0.113.5:1026 10.1.1.10:53012 198.51.100.53:53 198.51.100.53:53
!
! Outside local equals outside global: nothing on that side is translated.
Marking the interfaces
The router has to be told which interfaces face which side, because the whole model depends on it. An interface with neither designation participates in no translation at all, which is the first thing to check when a configuration looks complete and nothing is being translated.
This is also the constraint that makes some topologies awkward: traffic between two interfaces that are both marked inside is not translated, which is correct and occasionally not what somebody wanted.
! Without these two lines nothing is translated at all
R1(config)# interface GigabitEthernet0/0
R1(config-if)# description To the campus
R1(config-if)# ip nat inside
!
R1(config)# interface GigabitEthernet0/1
R1(config-if)# description To the internet
R1(config-if)# ip nat outside
!
! Confirm both are marked
R1# show ip nat statistics | include interfaces
What the entry records
A simple translation records an address pair. An overloaded translation records addresses and ports, because the port is what distinguishes one conversation from another when many share a global address. A fully extended entry additionally records the far end, which makes the entry specific to one conversation rather than to one host.
Which kind is created depends on how the translation was configured, and it matters for table size: fully extended entries are more numerous because a host talking to twenty destinations produces twenty of them rather than one.
Where the global addresses come from
Either an address on the router's own outside interface, or a pool of addresses routed to the router by whoever is upstream. The first needs nothing extra. The second needs the upstream to send that range here, and needs the router to answer for those addresses on the local segment if they are part of it.
Forgetting the upstream half is a common first-deployment failure: translation works, the table fills correctly, and replies never come back because nothing upstream knows where that range lives.
| Term | Host is on | Viewed from | Used in |
|---|---|---|---|
| Inside local | Inside | Inside | Every design |
| Inside global | Inside | Outside | Every design |
| Outside global | Outside | Outside | Overlapping address space |
| Outside local | Outside | Inside | Overlapping address space |
Which Flavour, and For What?
How do they differ?
A static translation is a permanent one-to-one mapping that works in both directions, so a server behind it can be reached from outside. A static translation restricted to a port maps one service rather than a whole host, which lets several servers share one address. A dynamic translation allocates from a pool when needed and does not support inbound connections. An overloaded dynamic translation shares one address among many hosts by distinguishing them by port, which is what almost every site actually runs.
A Deeper Dive into the Flavours
Static, for things that must be reachable
A permanent mapping in both directions. Traffic from the host is translated to the global address; traffic to the global address is translated to the host. That bidirectionality is the point and it is what makes a server publishable.
It consumes one global address per host, which is the cost. On a site with a handful of public addresses that limits how many servers can be published this way, which is why port-restricted mappings exist.
! One host, one address, both directions
R1(config)# ip nat inside source static 10.1.1.10 203.0.113.10
!
! Several services, one address, by port
R1(config)# ip nat inside source static tcp 10.1.1.10 443 203.0.113.5 443 extendable
R1(config)# ip nat inside source static tcp 10.1.1.11 25 203.0.113.5 25 extendable
R1(config)# ip nat inside source static udp 10.1.1.12 53 203.0.113.5 53 extendable
!
R1# show ip nat translations | include ---
Port-restricted static, and the keyword that matters
Mapping a service rather than a host lets one global address publish several servers. The keyword permitting several mappings to share one global address is required, and omitting it produces a configuration that accepts the first mapping and rejects or misbehaves on the second.
It is a small detail with a confusing failure, because the first service works perfectly and the second appears to have been configured and does nothing.
Dynamic, which is mostly historical
Allocating one global address per inside host from a pool. It needs as many addresses as there are simultaneously active hosts, which on any modern network is more than anyone has.
Its one advantage over the overloaded form is that each host has a distinct external address while its translation lasts, which occasionally matters for a service that distinguishes clients by address. It is otherwise superseded.
Overloaded, which is what everyone runs
Many hosts behind one address, distinguished by port. The table is larger because each conversation needs an entry rather than each host, and one address serves a large site comfortably.
The limit is ports rather than addresses. A single global address offers tens of thousands of usable ports, which is ample for a normal site and is a real constraint for one with thousands of users running applications that open many simultaneous connections each.
! Overloaded onto the outside interface address
R1(config)# ip access-list standard NAT-SOURCES
R1(config-std-nacl)# permit 10.1.0.0 0.0.255.255
!
R1(config)# ip nat inside source list NAT-SOURCES interface GigabitEthernet0/1 overload
!
! Or onto a pool, where one address is not enough
R1(config)# ip nat pool PUBLIC 203.0.113.20 203.0.113.23 netmask 255.255.255.248
R1(config)# ip nat inside source list NAT-SOURCES pool PUBLIC overload
!
R1# show ip nat statistics | include Total|Hits|Misses|pool
Selecting traffic by list or by policy
The traffic to be translated can be selected by an ordinary access list or by a policy that can also match on destination. The second is more expressive and it changes the kind of entry created: policy-based selection produces fully extended entries recording both ends.
That difference matters on a router with two upstream paths, where translating to a different address depending on which path is used requires matching on more than the source. It also increases table size, which is the trade.
The list must not deny
As with every classification list, a permit means "translate this" and a deny means "do not translate this, and continue evaluating". A deny is not a discard and using it as one produces traffic that leaves untranslated with a private source address, which is dropped somewhere upstream without explanation.
That failure is worth recognising because the symptom — some destinations reachable and others not — looks like a routing or firewall problem and the cause is in the translation list.
Where Does Translation Sit in the Journey?
What is the order?
Outbound, the router applies the inbound access list, makes its routing decision, then translates, then applies the outbound access list. Inbound, it applies the inbound access list, translates, then routes. So on the way out routing sees the untranslated address and on the way in it sees the translated one — and an access list on the outside interface always sees global addresses, in both directions, because translation is on the inside of it.
A Deeper Dive into the Order
Which address an access list matches
An access list applied inbound on the outside interface is evaluated before translation, so it matches the global address. An access list applied inbound on the inside interface is evaluated before translation too, and there the address is the local one.
The rule that makes this memorable: an access list on an interface always matches the addresses that are valid on that interface's side. Writing a rule on the outside interface using an inside host's private address will never match anything.
Routing on the way in
Inbound, translation happens before the routing decision, so the router routes toward the inside local address. This is what makes a published server work: the packet arrives addressed to a public address, is rewritten to the private one, and is then routed to it normally.
The consequence for the outside-address case is more subtle. Translating an outside host's address means the inside routes toward an address that does not exist anywhere — it is a fiction maintained by the router — and the router must have a route for that fictional range pointing at itself or the packets go nowhere.
Routing on the way out
Outbound, the routing decision is made before translation, using the original source and the original destination. For ordinary inside source translation nothing about the routing is affected, because only the source is being changed and routing does not consider the source.
It matters when policy routing is involved, because policy routing also runs before translation and therefore sees untranslated addresses. A policy matching on source has to be written against the private address, which is not always what the author expected.
! Outside interface lists are written against global addresses
R1(config)# ip access-list extended OUTSIDE-IN
R1(config-ext-nacl)# permit tcp any host 203.0.113.10 eq 443
R1(config-ext-nacl)# permit tcp any host 203.0.113.5 eq 25
R1(config-ext-nacl)# deny ip any any log
!
R1(config)# interface GigabitEthernet0/1
R1(config-if)# ip nat outside
R1(config-if)# ip access-group OUTSIDE-IN in
!
! Confirm the rule is being hit
R1# show ip access-lists OUTSIDE-IN | include matches
The overlapping address case
Two networks with the same private range, connected. Hosts on each side are translated into a range the other side can address. The inside is told to reach the far network at a fictional range, the router rewrites those addresses into the real ones, and the return traffic is rewritten back.
The requirement everyone misses is routing for the fictional range. The inside must have a route for it pointing at the translating router, because from the inside's perspective that range is a real destination reachable through that device.
! Overlapping ranges: translate the far side into a fiction
R1(config)# ip nat outside source static 10.1.1.50 172.16.99.50
!
! And give the inside a route to the fiction
R1(config)# ip route 172.16.99.0 255.255.255.0 Null0
!
! Inside hosts now reach 172.16.99.50, which is really 10.1.1.50
R1# show ip nat translations | include 172.16.99
Reaching an inside server by its public address, from inside
An inside host resolving a published server's name gets the public address and sends to it. The packet does not cross the boundary, so nothing translates it, and it arrives at the server with a destination the server does not recognise — or is routed out and back, which the ordinary model does not support.
Two answers. Give inside clients an internal name resolution that returns the private address, which is the clean solution and is a name service change rather than a network one. Or use the alternative translation model that is not tied to interface designations, which handles it and requires reworking the configuration. The first is almost always better.
Verifying the order rather than reasoning about it
The translation table and the access list counters together establish what is happening. An entry present with a list counter at zero means the list is on the wrong side of the translation. A list counter incrementing with no translation entry means the packet is being discarded before translation.
Those two comparisons resolve most order-of-operations confusion in under a minute, and they are more reliable than reasoning about the sequence from memory. Reading this once is not the same as being able to do it under time pressure, which is what repetition against realistic CCIE lab practice scenarios is for.
| Where | Direction | Sees | Write rules against |
|---|---|---|---|
| Outside interface | Inbound | Global addresses | The public address |
| Outside interface | Outbound | Global addresses | The public address |
| Inside interface | Inbound | Local addresses | The private address |
| Inside interface | Outbound | Local addresses | The private address |
| Policy routing | Outbound | Untranslated, both ends | The private address |
What Exhausts the Translation Table?
What fills it?
Two things. Default timeouts that are far longer than any conversation, so finished sessions occupy entries for hours after they ended. And a single misbehaving host — a scanner, a broken application, a compromised machine — opening sessions faster than they expire. When the table is full, new conversations cannot be translated, so nobody on the site can start anything new while existing sessions continue working. That symptom is distinctive and the cause is rarely looked for.
A Deeper Dive into Table Pressure
The default timeouts
A completed connection's entry is held for a period measured in hours by default, on the reasoning that a connection may resume. On a site where each user opens hundreds of short-lived connections an hour, that produces an enormous number of entries representing nothing.
Shortening them is safe within reason and is the single most effective step against table pressure. The values that matter are the one for completed connections and the one for connectionless traffic, and both can be reduced substantially without affecting anything users notice.
! Defaults are generous. These are not aggressive.
R1(config)# ip nat translation timeout 3600
R1(config)# ip nat translation tcp-timeout 3600
R1(config)# ip nat translation udp-timeout 120
R1(config)# ip nat translation icmp-timeout 30
R1(config)# ip nat translation finrst-timeout 30
R1(config)# ip nat translation syn-timeout 30
!
R1# show ip nat statistics | include Total active|expired
Capping what one host can consume
A limit on entries per host stops one machine from filling the table for everyone. It is a single line, it has no effect on normal use, and it converts a site-wide outage into a problem for one host.
The limit should be well above what any legitimate application needs and well below the table size. Something in the low hundreds is usually right for a client machine and higher for a server that legitimately opens many outbound connections.
! One host cannot take the table down for everyone
R1(config)# ip nat translation max-entries all-host 300
R1(config)# ip nat translation max-entries 20000
!
! Who is using the most?
R1# show ip nat translations | count 10.1.
R1# show ip nat statistics | include Total active translations|limit
show ip nat statistics shows the active translation count at or near the platform limit. Fix: shorten the translation timeouts, cap the entries any single host may hold, and identify the host responsible — there usually is one.Finding the host responsible
Counting entries per inside address identifies it immediately, and it is almost always one machine rather than general growth. A scanner, a peer-to-peer application, a piece of malware, or an application with a connection leak.
Once identified, the per-host cap prevents a recurrence regardless of what the next such machine turns out to be running. That is the more durable fix than dealing with each incident individually.
Port availability, which is the other limit
With overloading, each global address provides a finite set of ports. A large site behind a single address can exhaust them even with a table that is nowhere near full, and the symptom is the same: new conversations fail while existing ones continue.
Adding addresses to the pool multiplies the available ports directly and is the straightforward fix. Sizing this in advance means estimating concurrent conversations per user and multiplying, which is a rough calculation and considerably better than none.
Clearing entries
Entries can be cleared, which frees the table immediately and drops every connection using them. It is a blunt instrument appropriate to an emergency and not to routine operation.
Clearing selectively — one host's entries rather than all — is available and is the right form when one machine has been identified. Clearing everything during business hours drops every session on the site.
! Selective, not everything
R1# clear ip nat translation inside 10.1.1.55 *
!
! Everything - drops every session on the site
R1# clear ip nat translation *
!
! What the table looks like now
R1# show ip nat statistics
What to monitor
The active translation count against the platform's capacity, which is the direct measure. The rate of new translations, whose sudden increase identifies a problem before the table fills. And the highest per-host count, which names the machine responsible without any investigation.
The third is the most useful and the least commonly collected. It turns the diagnosis of a site-wide outage into reading one number.
Which Failures Are Not Translation Failures?
What else causes them?
Four things that present as translation problems. An application-layer helper rewriting addresses inside the payload, correctly or incorrectly. A protocol that carries addresses in its data and has no helper, so the rewriting never happens. A failover that discards the table, breaking every session at once. And asymmetric paths, where traffic leaves through a translating device and returns through one that knows nothing about it. None of these is fixed by changing the translation configuration.
A Deeper Dive into the Other Causes
Helpers that rewrite the payload
Some protocols carry addresses inside their data. Translating only the header leaves the payload referring to a private address, which the far end then tries to use. Helpers exist for the common protocols and rewrite the payload as well.
They work well and they occasionally rewrite something they should not, particularly for protocols whose modern variants differ from what the helper expects. The characteristic symptom is a call or a transfer that establishes and then fails in a way that does not correspond to anything in the network.
Disabling a helper
Where a helper is interfering, disabling it for that protocol is a single line and is a well-established fix for certain telephony deployments. Doing so requires the application to handle the translation itself, which modern implementations generally do.
It is worth knowing as a specific remedy because the symptom is confusing and the fix is not obvious: telephony that registers correctly and has no audio in one direction is very often this.
! A helper that is interfering with a modern implementation
R1(config)# no ip nat service sip tcp port 5060
R1(config)# no ip nat service sip udp port 5060
!
! What is enabled
R1# show running-config | include ip nat service
R1# show ip nat statistics | include ALG|service
Protocols with no helper
Anything carrying addresses in its data with no corresponding helper will not work through translation without the application handling it. Modern protocols generally do handle it, because translation has been ubiquitous for decades; older and bespoke ones frequently do not.
The answer for those is a static translation with no port restriction, so the address relationship is stable and the application's assumptions hold. It costs a public address and it works.
Failover, which discards everything
The table lives in memory on one device. A failover to a second device starts with an empty table, so every existing conversation is broken — not degraded, broken, because the return traffic has no entry to reverse.
Where that matters, the two devices must share state, which is a specific feature that has to be configured and verified rather than something redundancy provides on its own. Where it does not matter, the behaviour should at least be understood so that a failover test's results are not a surprise.
Asymmetric paths
Traffic leaving through one router and returning through another means the return packet reaches a device with no entry for it. It is discarded, and the symptom is a connection that establishes in one direction and never completes.
This arises whenever there are two paths and the routing does not force symmetry. Either the design must guarantee both directions use the same device, or the two devices must share state. There is no configuration on a single router that fixes it.
A diagnostic order
Is an entry created? If not, the traffic is not matching the selection or not crossing between a marked inside and a marked outside interface. If an entry is created, is there return traffic? If not, the global address is not routed back or an access list is discarding it. If there is return traffic and the application still fails, the problem is in the payload and the question is about helpers.
Three questions, in that order, and each one is answered by one command. Working in a different order is what makes translation feel unpredictable.
! Three questions, in order
R1# show ip nat translations | include 10.1.1.10
R1# show ip nat statistics | include Hits|Misses
R1# show ip access-lists OUTSIDE-IN | include matches
!
! And when only one application is affected
R1# show running-config | include ip nat service
R1# debug ip nat detailed
What to keep documented
Every static mapping and what it publishes, because a mapping outlives the reason it was created and a published service nobody remembers is a genuine exposure. The pool ranges and who routes them here. The timeout values and why they were changed. And whether state is shared between redundant devices, so that a failover's consequences are known before it happens.
The first of those is the one that matters for security. An audit of static mappings against services that should be published is a short exercise that regularly finds something.
Blueprint framing
The CCIE Enterprise Infrastructure v1.1 blueprint covers network address translation within its infrastructure services domain. What is examined is generally the terminology, the flavours and the order of operations — particularly which address an access list matches — rather than a large configuration.
| Symptom | Actual cause | First check |
|---|---|---|
| No entry is created | Selection or interface marking | Interfaces marked inside and outside |
| Entry created, no reply | Global range not routed back | Upstream route for the pool |
| One application fails | A payload helper | Which helpers are enabled |
| Rule matches nothing | List sees the other address | Which side the list is on |
| Everything drops on failover | Table is not shared | State sharing configuration |
| Establishes then stalls | Asymmetric return path | Both devices' tables |
Conclusion
The four terms decode with one rule: the first word says which side the host is on, the second says which side you are looking from. Most designs use only the inside pair; the outside pair exists for overlapping address space, which is where the order of operations stops being academic and becomes the thing that decides whether packets arrive.
That order is the subject. Outbound, the router routes and then translates. Inbound, it translates and then routes. So an access list on the outside interface matches global addresses in both directions, a rule written there against a server's private address will never match anything, and a policy routing statement sees untranslated addresses because it runs before translation as well. One rule covers the access list question entirely: a list matches the addresses that are valid on the side of the interface it is applied to.
What fills the table is long default timeouts and one misbehaving host, and the symptom — existing sessions working while nothing new can start — is distinctive enough to diagnose from the description. Shorten the timeouts, cap what one host may consume, and collect the highest per-host count so that the next incident is one number rather than an investigation. And when a single application fails through an otherwise healthy translation, stop looking at the translation: the address is in the payload, and the question is which helper is or is not rewriting it. More CCIE Enterprise Infrastructure material — labs, protocol breakdowns and study guides — is collected on the SPOTO CCIE site.
External Links
- RFC 3022 — Traditional IP Network Address Translator
- RFC 2663 — IP Network Address Translator Terminology
- RFC 4787 — NAT Behavioral Requirements for Unicast UDP
- RFC 5382 — NAT Behavioral Requirements for TCP
- RFC 3235 — Application Design Guidelines for NAT
- RFC 1918 — Address Allocation for Private Internets
- Cisco Learning Network — CCIE Enterprise Infrastructure
Reference Notes
- RFC 2663 defines the terminology for address translation, including the distinction between an address as seen from the inside and as seen from the outside.
- RFC 2663 describes the translation binding and the state a translator must hold in order to reverse the translation for returning traffic.
- RFC 3022 specifies traditional address translation, covering both basic one-to-one translation and translation with port multiplexing.
- RFC 3022 notes that a translator with port multiplexing supports outbound-initiated sessions, and that inbound sessions require a statically configured binding.
- RFC 3022 describes the need for application-level gateways where a protocol carries addresses within its payload.
- RFC 4787 specifies behavioural requirements for translation of unicast UDP, including recommended mapping timers with a minimum on the order of minutes.
- RFC 5382 specifies behavioural requirements for translation of TCP, including recommended idle timers for established and transitory connections.
- RFC 5382 recommends that a translator retain state for an established connection for a substantial period, which is the basis of the long default timeouts.
- RFC 3235 provides design guidelines for applications intended to operate across translators, including avoiding addresses in payloads.
- RFC 1918 allocates the private address ranges whose use behind a translator is the ordinary enterprise arrangement.
- Cisco documentation describes the order of operations for translation, in which routing precedes translation for inside-to-outside traffic and translation precedes routing for outside-to-inside traffic.
- The CCIE Enterprise Infrastructure v1.1 unified exam topics include network address translation within the infrastructure services domain.