GRE over IPsec and Static NAT
- By Joe Astorino
- April 1, 2017
- 9 Comments
Introduction
I have recently been studying IPsec based VPNs and kept running into the same struggle – Many sources out there claim that when implementing GRE over IPsec, if the tunnel traffic passes through a NAT device, then you must implement tunnel mode. Notably, http://www.cisco.com/c/en/us/td/docs/solutions/Enterprise/WAN_and_MAN/P2P_GRE_IPSec/P2P_GRE/2_p2pGRE_Phase2.html#wp116954.
If the crypto tunnel transits either a Network Address Translation (NAT) or Port Address Translation (PAT) device, tunnel mode is required
This implies that transport mode is not compatible with GRE over IPsec going through a NAT device. I thought fairly deeply about the problem for a while, and that didn’t make any sense, so I decided to lab it up. I learned a lot, and what you find here might surprise you! No matter the topic, when you are studying, never stop asking the questions why and how does that work.
Here is the lab topology we will be working on today:
R1 and R3 will be establishing a GRE over IPsec tunnel in all the examples that will follow. Obviously, the tunnel traffic passes through R2. R2 will be configured to static NAT R1 from 10.0.12.1 to 10.0.23.1. Thus, the tunnel traffic between R1 and R3 clearly goes through a NAT device. From R1’s perspective, the tunnel source is 10.0.12.1 and the tunnel destination is 10.0.23.3. However, from R3’s perspective, the tunnel source is 10.0.23.3 and the tunnel destination is 10.0.23.1 (R1’s inside global address).
Note that we will run OSPF between all routers so that R1 and R3 will know how to get to the respective tunnel destination addresses. Once the tunnel interfaces come up, we will also run EIGRP over the tunnel to advertise the loopback addresses.
Initial Configurations
R1:
interface Loopback0 ip address 1.1.1.1 255.255.255.255 ! interface GigabitEthernet1 ip address 10.0.12.1 255.255.255.0 ! interface Tunnel0 ip address 192.168.1.1 255.255.255.0 tunnel source GigabitEthernet1 tunnel destination 10.0.23.3 ! router eigrp 1 network 1.1.1.1 0.0.0.0 network 192.168.1.0 passive-interface default no passive-interface Tunnel0 ! router ospf 1 passive-interface default no passive-interface GigabitEthernet1 network 10.0.12.0 0.0.0.255 area 0
R2:
interface GigabitEthernet1.100 encapsulation dot1Q 100 ip address 10.0.12.2 255.255.255.0 ip nat inside ip ospf priority 255 ! interface GigabitEthernet1.101 encapsulation dot1Q 101 ip address 10.0.23.2 255.255.255.0 ip nat outside ip ospf priority 255 ! ip nat inside source static 10.0.12.1 10.0.23.1 ! router ospf 1 network 10.0.0.0 0.0.255.255 area 0 default-information originate always
R3:
interface Loopback0 ip address 3.3.3.3 255.255.255.255 ! interface GigabitEthernet1 ip address 10.0.23.3 255.255.255.0 ! interface Tunnel0 ip address 192.168.1.3 255.255.255.0 tunnel source GigabitEthernet1 tunnel destination 10.0.23.1 ! router eigrp 1 network 3.3.3.3 0.0.0.0 network 192.168.1.0 passive-interface default no passive-interface Tunnel0 ! router ospf 1 passive-interface default no passive-interface GigabitEthernet1 network 10.0.23.0 0.0.0.255 area 0
Transport Mode Using Crypto Maps
Let’s put this to the test then. If the article I linked to in the introduction is correct, this shouldn’t be possible, right?
R1:
crypto isakmp policy 10 encr 3des hash md5 authentication pre-share ! crypto isakmp key cisco address 0.0.0.0 crypto ipsec transform-set ESP-3DES-MD5 esp-3des esp-md5-hmac mode transport ! ip access-list extended R1-R3 permit gre host 10.0.12.1 host 10.0.23.3 ! crypto map CRYPTO 10 ipsec-isakmp set peer 10.0.23.3 set transform-set ESP-3DES-MD5 match address R1-R3 ! interface GigabitEthernet1 crypto map CRYPTO
R3:
crypto isakmp policy 10 encr 3des hash md5 authentication pre-share ! crypto isakmp key cisco address 0.0.0.0 crypto ipsec transform-set ESP-3DES-MD5 esp-3des esp-md5-hmac mode transport ! ip access-list extended R1-R3 permit gre host 10.0.23.3 host 10.0.23.1 ! crypto map CRYPTO 10 ipsec-isakmp set peer 10.0.23.1 set transform-set ESP-3DES-MD5 match address R1-R3 ! interface GigabitEthernet1 crypto map CRYPTO
Notice how the crypto map peer on R3 is pointing to the mapped address of R1…Now, does it work?
R1:
We can see our EIGRP adjacency over the tunnel came up, which is a great sign to start with…
R1#sh ip eigrp neigh EIGRP-IPv4 Neighbors for AS(1) H Address Interface Hold Uptime SRTT RTO Q Seq (sec) (ms) Cnt Num 0 192.168.1.3 Tu0 14 00:00:37 5 1470 0 30
Do we have R3’s loopback route learned over the tunnel?
R1#sh ip route eigrp | b Gateway Gateway of last resort is 10.0.12.2 to network 0.0.0.0 3.0.0.0/32 is subnetted, 1 subnets D 3.3.3.3 [90/27008000] via 192.168.1.3, 00:02:09, Tunnel0
Finally, can we ping?
R1#ping 3.3.3.3 so lo0 Type escape sequence to abort. Sending 5, 100-byte ICMP Echos to 3.3.3.3, timeout is 2 seconds: Packet sent with a source address of 1.1.1.1 !!!!! Success rate is 100 percent (5/5), round-trip min/avg/max = 4/5/7 ms
Some IPsec verifications…
Phase 1 was fine
R1#sh crypto isakmp sa IPv4 Crypto ISAKMP SA dst src state conn-id status 10.0.12.1 10.0.23.3 QM_IDLE 1007 ACTIVE
Phase 2 is fine…Notice that NAT-T is being used automagically, as it is detected in IKEv1 main mode.
R1#sh crypto ipsec sa interface: GigabitEthernet1 Crypto map tag: CRYPTO, local addr 10.0.12.1 protected vrf: (none) local ident (addr/mask/prot/port): (10.0.12.1/255.255.255.255/47/0) remote ident (addr/mask/prot/port): (10.0.23.3/255.255.255.255/47/0) current_peer 10.0.23.3 port 4500 PERMIT, flags={origin_is_acl,} #pkts encaps: 10, #pkts encrypt: 10, #pkts digest: 10 #pkts decaps: 11, #pkts decrypt: 11, #pkts verify: 11 #pkts compressed: 0, #pkts decompressed: 0 #pkts not compressed: 0, #pkts compr. failed: 0 #pkts not decompressed: 0, #pkts decompress failed: 0 #send errors 0, #recv errors 0 local crypto endpt.: 10.0.12.1, remote crypto endpt.: 10.0.23.3 plaintext mtu 1458, path mtu 1500, ip mtu 1500, ip mtu idb GigabitEthernet1 current outbound spi: 0x57C8D38A(1472779146) PFS (Y/N): N, DH group: none inbound esp sas: spi: 0xE987C51D(3917989149) transform: esp-3des esp-md5-hmac , in use settings ={Transport UDP-Encaps, } conn id: 2041, flow_id: CSR:41, sibling_flags FFFFFFFF80004008, crypto map: CRYPTO sa timing: remaining key lifetime (k/sec): (4607998/3580) IV size: 8 bytes replay detection support: Y Status: ACTIVE(ACTIVE) inbound ah sas: inbound pcp sas: outbound esp sas: spi: 0x57C8D38A(1472779146) transform: esp-3des esp-md5-hmac , in use settings ={Transport UDP-Encaps, } conn id: 2042, flow_id: CSR:42, sibling_flags FFFFFFFF80004008, crypto map: CRYPTO sa timing: remaining key lifetime (k/sec): (4607999/3580) IV size: 8 bytes replay detection support: Y Status: ACTIVE(ACTIVE) outbound ah sas: outbound pcp sas:
So, myth busted – GRE over IPsec through a static NAT works just fine. This makes sense when you think about the packet structure going on here. Here is what things look like when R1 sends pings to R3:
[Outside IP][UDP][ESP][GRE][Inside IP][ICMP]
The inside IP header in this case is 1.1.1.1 –> 3.3.3.3. The outside IP header is the header tacked on during GRE encapsulation. Because we are working with Transport mode, it goes outside the ESP encapsulation and looks like this: 10.0.12.1 –> 10.0.23.3. When R3 receives the packet, it decrypts it, and finds a GRE packet inside. No worries.
Now, what is particular interesting about this solution is if you look at the IPsec SA from the perspective of R3…
R3:
R3#sh crypto ipsec sa | i local ident|remote ident local ident (addr/mask/prot/port): (10.0.23.3/255.255.255.255/47/0) remote ident (addr/mask/prot/port): (10.0.23.1/255.255.255.255/47/0)
Notice that the proxy identity negotiated from R1’s point of view is GRE (IP protocol 47) between 10.0.12.1 and 10.0.23.3, while from R3’s point of view, it is between 10.0.23.3 and 10.0.23.1, R1’s mapped address. So, the proxy identities in this case are not mirrored!
Tunnel Mode Using Crypto Maps
OK, we have seen that using transport mode is fine. Let’s try tunnel mode. After all, according to the Cisco article and other books I have read, this should work just fine…in fact, it is the “preferred” method, right? Before I made the below changes, I shut down the tunnel interfaces on both sides, and cleared the crypto and isakmp SAs on both sides
R1 and R3:
crypto ipsec transform-set ESP-3DES-MD5 esp-3des esp-md5-hmac mode tunnel
Now, we will bring the tunnel interfaces back up on both sides and see what happens. Here is some output from R1. As you can see, phase 1 completed fine, but the EIGRP neighbor never comes up. Also, Phase 2 does not look good…
R1#sh ip int bri | i Tunnel Tunnel0 192.168.1.1 YES NVRAM up up R1#sh crypto isakmp sa IPv4 Crypto ISAKMP SA dst src state conn-id status 10.0.12.1 10.0.23.3 QM_IDLE 1008 ACTIVE R1#sh ip eigrp neigh EIGRP-IPv4 Neighbors for AS(1) R1#sh crypto ipsec sa interface: GigabitEthernet1 Crypto map tag: CRYPTO, local addr 10.0.12.1 protected vrf: (none) local ident (addr/mask/prot/port): (10.0.12.1/255.255.255.255/47/0) remote ident (addr/mask/prot/port): (10.0.23.3/255.255.255.255/47/0) current_peer 10.0.23.3 port 500 PERMIT, flags={origin_is_acl,ipsec_sa_request_sent} #pkts encaps: 0, #pkts encrypt: 0, #pkts digest: 0 #pkts decaps: 1, #pkts decrypt: 1, #pkts verify: 1
Why? Let’s debug
R1#debug crypto ipsec Crypto IPSEC debugging is on *Apr 2 01:53:27.641: IPSEC(validate_proposal_request): proposal part #1 *Apr 2 01:53:27.641: IPSEC(validate_proposal_request): proposal part #1, (key eng. msg.) INBOUND local= 10.0.12.1:0, remote= 10.0.23.3:0, local_proxy= 10.0.23.1/255.255.255.255/47/0, remote_proxy= 10.0.23.3/255.255.255.255/47/0, protocol= ESP, transform= esp-3des esp-md5-hmac (Tunnel-UDP), lifedur= 0s and 0kb, spi= 0x0(0), conn_id= 0, keysize= 0, flags= 0x0 *Apr 2 01:53:27.641: Crypto mapdb : proxy R1#_match src addr : 10.0.23.1 dst addr : 10.0.23.3 protocol : 47 src port : 0 dst port : 0 *Apr 2 01:53:27.641: Crypto mapdb : proxy_match src addr : 10.0.23.1 dst addr : 10.0.23.3 protocol : 47 src port : 0 dst port : 0 *Apr 2 01:53:27.641: map_db_find_best did not find matching map *Apr 2 01:53:27.641: IPSEC(ipsec_process_proposal): proxy identities not supported
OK…so what is this telling us? R3 is sending us a proposal for the proxy identities here (what traffic should be encrypted). R3 is proposing that GRE traffic between 10.0.23.1 (R1’s mapped address) and 10.0.23.3 be encrypted. However, that doesn’t match what R1 thinks. R1 think it should be between 10.0.12.1 (R1’s real address) and 10.0.23.3. Now, despite that sounding pretty crappy, we just saw how non-mirrored proxy identities appeared to be just fine with transport mode, so what changed here? Why is it OK in transport mode but not in tunnel mode? The answer is in the headers. Let’s say the routers did allow this to happen. What would ping traffic look like between R3 and R1 from a header / data plane perspective when the packets reach R1? Like this:
[Outside IP][UDP][ESP][GRE IP][GRE][Inside IP][ICMP] where…
Outside IP: 10.0.23.3 –> 10.0.12.1 (this is after R2 NATs the destination from 10.0.23.1 back to 10.0.12.1 in transit)
GRE IP: 10.0.23.3 –> 10.0.23.1 – This is R3’s perspective when the packet leaves R3. However, remember this is encrypted in transit and encrypted when it arrives at R1…
Inside IP: 3.3.3.3 –> 1.1.1.1
Here is where things would break down. Say R1 received the packet. It decrypts the packet and sees inside the packet an IP header (The GRE IP header) destined to 10.0.23.1 (R1’s mapped address). R1 has no idea what that is, so it throws the packet away. Tunnel mode using GRE/IPsec through a NAT device: Epic. Fail. Basically what is happening here is the routers are protecting us from ourselves. The routers know that if these proposals were accepted, the data plane would break down when using tunnel mode. So, instead of allowing that to happen, we get proxy identities are unsupported, and thus the phase II never completes properly.
OK, now could we get “creative” in a situation where for some reason we HAD to run tunnel mode in this situation? We can! As we saw above, the root cause of this break down is the fact that in the encrypted payload we have an IP header with a destination of the mapped address of R1. Since R1 has no idea what this is, it can’t process the packet. So, what if R1 DID have an idea of what 10.0.23.1 was? What if it existed on R1 itself? Enter the loopback address hack. What we will do is add a loopback interface on R1 that matches R1’s mapped address. That way, when the packets from R3 arrive and are decrypted, R1 will have a way to process the GRE packets sitting inside.
R1:
interface Loopback100 ip address 10.0.23.1 255.255.255.255 ! ! ip access-list extended R1-R3 no permit gre host 10.0.12.1 host 10.0.23.3 permit gre host 10.0.23.1 host 10.0.23.3 ! interface Tunnel0 tunnel source Loopback100
Will it work? You bet…
R1#ping 3.3.3.3 so lo0 Type escape sequence to abort. Sending 5, 100-byte ICMP Echos to 3.3.3.3, timeout is 2 seconds: Packet sent with a source address of 1.1.1.1 !!!!! Success rate is 100 percent (5/5), round-trip min/avg/max = 5/5/5 ms ! R1#sh crypto ipsec sa | i pkts encap|pkts decap #pkts encaps: 19, #pkts encrypt: 19, #pkts digest: 19 #pkts decaps: 40, #pkts decrypt: 40, #pkts verify: 40
Transport Mode with Tunnel Interfaces
OK, so far we have seen that at least with a crypto map implementation of GRE/IPsec through a NAT device, transport mode works just fine out of the box, while tunnel mode doesn’t work at all. We also saw a clever method we could use to force tunnel mode into submission. In theory, this should all work exactly the same with if we get rid of the crypto maps and instead implement GRE over IPsec using tunnel interfaces and IPsec profiles instead. Let’s try, starting with transport mode again. Note that before moving on here, I have shut down Lo100 on R1, and cleared the SAs again, as well as shut down the tunnel interfaces on both sides
R1:
crypto ipsec transform-set ESP-3DES-MD5 esp-3des esp-md5-hmac mode transport ! crypto ipsec profile IPSEC set transform-set ESP-3DES-MD5 ! interface G1 no crypto map CRYPTO ! interface tunnel0 tunnel source G1 tunnel protection ipsec profile IPSEC
R3:
crypto ipsec transform-set ESP-3DES-MD5 esp-3des esp-md5-hmac mode transport ! crypto ipsec profile IPSEC set transform-set ESP-3DES-MD5 ! interface G1 no crypto map CRYPTO ! interface tunnel0 tunnel source G1 tunnel protection ipsec profile IPSEC
OK, let’s try again. I will bring the tunnels back up and see what happens. As you can see below, the tunnel came right up, EIGRP came up, and I was able to ping. This works for the exact same reason transport mode worked with crypto map implementation, so we won’t go too deep here.
R1#ping 3.3.3.3 so lo0 Type escape sequence to abort. Sending 5, 100-byte ICMP Echos to 3.3.3.3, timeout is 2 seconds: Packet sent with a source address of 1.1.1.1 !!!!! Success rate is 100 percent (5/5), round-trip min/avg/max = 5/5/6 ms
Tunnel Mode with Tunnel Interfaces
Since an IPsec profile applied to a GRE/IPv4 tunnel interface is essentially the exact same thing as having a GRE/IPv4 tunnel interface with crypto maps configured on the physical interface to protect the GRE traffic between the tunnel endpoints, we will not see much change here. If we simply change our transform-set to tunnel mode here without the loopback hack we employed earlier, it will fail for the exact same reason it did when we tried it with crypto maps. Let’s make sure:
R1 and R3:
crypto ipsec transform-set ESP-3DES-MD5 esp-3des esp-md5-hmac mode tunnel
Shut down the tunnels, clear the SA’s and bring the tunnels back up…Again a debug crypto ipsec on R1 shows the following:
*Apr 2 02:29:42.251: IPSEC(validate_proposal_request): proposal part #1 *Apr 2 02:29:42.251: IPSEC(validate_proposal_request): proposal part #1, (key eng. msg.) INBOUND local= 10.0.12.1:0, remote= 10.0.23.3:0, local_proxy= 10.0.23.1/255.255.255.255/47/0, remote_proxy= 10.0.23.3/255.255.255.255/47/0, protocol= ESP, transform= esp-3des esp-md5-hmac (Tunnel-UDP), lifedur= 0s and 0kb, spi= 0x0(0), conn_id= 0, keysize= 0, flags= 0x0 *Apr 2 02:29:42.251: map_db_find_best did not find matching map *Apr 2 02:29:42.251: IPSEC(ipsec_process_proposal): proxy identities not supported
OK, then by the same logic as before, what if we use the loopback hack? So, lets put Lo100 back into service, and alter the tunnel configuration on R1 so that it sources things from Lo100:
interface Loopback100 ip address 10.0.23.1 255.255.255.255 no shut ! interface Tunnel0 tunnel source lo100
Now, does it work? No! The EIGRP neighbor is never established this time. What could go wrong? Debug crypto ipsec on R1 this time reveals the following:
*Apr 2 02:37:37.095: IPSEC(validate_proposal_request): proposal part #1 *Apr 2 02:37:37.095: IPSEC(validate_proposal_request): proposal part #1, (key eng. msg.) INBOUND local= 10.0.12.1:0, remote= 10.0.23.3:0, local_proxy= 10.0.23.1/255.255.255.255/47/0, remote_proxy= 10.0.23.3/255.255.255.255/47/0, protocol= ESP, transform= esp-3des esp-md5-hmac (Tunnel-UDP), lifedur= 0s and 0kb, spi= 0x0(0), conn_id= 0, keysize= 0, flags= 0x0 *Apr 2 02:37:37.095: IPSEC(ipsec_process_ proposal): invalid local address 10.0.12.1 *Apr 2 02:37:54.575: IPSEC(sa_request): , (key eng. msg.) OUTBOUND local= 10.0.23.1:500, remote= 10.0.23.3:500, local_proxy= 10.0.23.1/255.255.255.255/47/0, remote_proxy= 10.0.23.3/255.255.255.255/47/0, protocol= ESP, transform= esp-3des esp-md5-hmac (Tunnel), lifedur= 3600s and 4608000kb, spi= 0x0(0), conn_id= 0, keysize= 0, flags= 0x0
OK, this looks familiar. This is saying that R3 sends us a proposal. From R3’s perspective it is sending the packet to 10.0.23.1. R2 then NATs the destination to 10.0.12.1 and the packet arrives at R1. That is the INBOUND local= 10.0.12.1, remote= 10.0.23.3 part. So we are receiving a packet FROM 10.0.23.3 destined TO 10.0.12.1. Inside that proposal, R3 is proposing that all GRE traffic between 10.0.23.1 and 10.0.23.3 be encrypted. R1 is actually on board with that, as you can see in the OUTBOUND proposal. This is because we are sourcing our tunnel interface on R1 from Lo100. So, why is it broken?
It is broken because when R2 does the NAT it changes the destination address to 10.0.12.1, the IP on R1 G1. For this to work with a tunnel interface, since we are sourcing things from a Loopback, the packets need to be ultimately destined to that loopback address, 10.0.23.1 on R1.
This is where things get fairly insane…
R1:
interface Loopback100 ip nat inside ! interface GigabitEthernet1 ip nat outside ! ip nat inside source static 10.0.23.1 10.0.12.1
So now, R3 sends the proposal, and it is from 10.0.23.3 –> 10.0.23.1. R2 NATs the packet and sends to R1. It is now 10.0.23.3 –> 10.0.12.1. The packet arrives on R1, and R1 NATs the destination again. Finally we have 10.0.23.3 –> 10.0.23.1 on R1, and away we go…
R1#ping 3.3.3.3 so lo0 Type escape sequence to abort. Sending 5, 100-byte ICMP Echos to 3.3.3.3, timeout is 2 seconds: Packet sent with a source address of 1.1.1.1 !!!!! Success rate is 100 percent (5/5), round-trip min/avg/max = 5/5/5 ms
Weeeeeeeeee
Summary
With regards to GRE over IPsec through a static NAT device, I can conclude the following based on my own lab testing:
- Transport mode works fine with both crypto map and tunnel interface implementation
- Tunnel mode is broken by default with both crypto map and tunnel interface implementation due to the way tunnel mode IPsec interacts with GRE tunnel interfaces
- Tunnel mode can be made to work by using some hacks, although in the real world that would be a really really nasty way to do things. In something like the CCIE lab…all bets are off.
Keep in mind, the purpose of this exercise was explicitly to test GRE over IPsec. When you have other technologies involved, there are certainly other options. For example, VTI interfaces, DMVPN, etc…the purpose of this lab was to test and validate GRE over IPsec L2L explicitly.
Thanks for playing!
Nice article, but given the day of publication I’ll take it with a grain of salt.
Nothing to do with April fools, I assure you. Coincidence.
You never showed if EIGRP in the last part came up! I don’t know how the story ends and I have to lab it up now.
It did. After the necessary static NAT on R1 of course.
Excellent post, Joe. I hope you have the time to post more blog content in the future. I’m really looking forward to it!
As always, great work, Joe! Keep up the good labbing!
[…] GRE over IPSec and Static NAT […]
Will simple GRE form in this Setup without using the crypto map’s on the r2 interface ?
Great post which may saves lot of time…