This is an illustrated guide that shows how to configure the various types of Network Address Translation (NAT) on the Juniper SRX series. Each example lists the configuration on the SRX, as well as what the client and server on either side of the SRX doing the NATing see and experience through working examples.
Here we'll configure what might be arguablely the simplest form of NAT, static NAT. We'll create a bidirectional NAT session between the client and server. Even though the client and server are in different subnets, we will have to connect to each other through their local IP subnet by mapping a portion of the IP space to be NAT'ed to the other subnet.
To prove the point, we'll remove the default gateways from both the client and server. No routing going on here!
removing default routes from client
root@client:~# route del default gw 192.168.200.1 root@client:~# netstat -rn Kernel IP routing table Destination Gateway Genmask Flags MSS Window irtt Iface 192.168.200.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1 root@client:~#
removing default routes from server
root@server:~# route del default gw 10.80.80.1 root@server:~# netstat -rn Kernel IP routing table Destination Gateway Genmask Flags MSS Window irtt Iface 10.80.80.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1 root@server:~#
Next we'll map 192.168.200.200/29 to 10.80.80.80/29, and 10.80.80.200/29 to 192.168.200.80/29. This way any host on the 192.168.200.0/24 subnet can connect to the range of 10.80.80.80/29 by pointing at 192.168.200.200/29.
Here is the SRX config, complete with the needed proxy-arp entries.
SRX config for static NAT
juniper@SRX# show static { rule-set STATIC-NAT-UNTRUST { from zone UNTRUST; rule STATIC-NAT-UNTRUST { match { source-address 192.168.200.80/29; destination-address 192.168.200.200/29; } then { static-nat { prefix { 10.80.80.80/29; } } } } } } proxy-arp { interface ge-0/0/4.0 { address { 192.168.200.200/29; } } interface ge-0/0/3.0 { address { 10.80.80.200/29; } } }
Now to test, we'll start up a netcat session on the server.
server listening on port 5000
juniper@server:~$ nc -l 5000 < testfile
And then we'll connect to it from the client through it's to-be NAT'd IP
client connecting to server through NAT'd IP
juniper@client:~$ telnet 192.168.200.200 5000 Trying 192.168.200.200... Connected to 192.168.200.200. Escape character is '^]'. THIS IS ANOTHER FLURKING TEST\! Connection closed by foreign host. juniper@client:~$
On the SRX we see the following session:
session on SRX with static NAT
juniper@SRX# run show security flow session Session ID: 3801, Policy name: ACCEPT-LOG/4, Timeout: 1786, Valid In: 192.168.200.81/45499 --> 192.168.200.200/5000;tcp, If: ge-0/0/4.0, Pkts: 3, Bytes: 170 Out: 10.80.80.80/5000 --> 192.168.200.81/45499;tcp, If: ge-0/0/3.0, Pkts: 2, Bytes: 112 Total sessions: 1 [edit security nat] juniper@SRX#
We can repeat the test with UDP traffic instead.
UDP listener on port 5000 on server
juniper@server:~$ nc -lu 5000 < testfile
Client connects. Note that with UDP traffic and netcat, you must hit enter to actually send the first packet, and control-c to close the session.
client connecting to UDP listener on server
juniper@client:~$ nc -u 192.168.200.200 5000THIS IS ANOTHER FLURKING TEST\! ^C juniper@client:~$
And a UDP flow on the SRX:
UDP session on SRX with static NAT
juniper@SRX# run show security flow session Session ID: 4095, Policy name: ACCEPT-LOG/4, Timeout: 28, Valid In: 192.168.200.81/49647 --> 192.168.200.200/5000;udp, If: ge-0/0/4.0, Pkts: 1, Bytes: 29 Out: 10.80.80.80/5000 --> 192.168.200.81/49647;udp, If: ge-0/0/3.0, Pkts: 1, Bytes: 60 Total sessions: 1 [edit security nat] juniper@SRX#
We can even send a ping through!
ping test on client
juniper@client:~$ ping -c 1 192.168.200.207 PING 192.168.200.207 (192.168.200.207) 56(84) bytes of data. 64 bytes from 192.168.200.207: icmp_req=1 ttl=63 time=4.78 ms --- 192.168.200.207 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 4.785/4.785/4.785/0.000 ms juniper@client:~$
And the matching sessions on the SRX for the ICMP traffic.
ICMP sessions on SRX with static NAT
juniper@SRX# run show security flow session Session ID: 4129, Policy name: ACCEPT-LOG/4, Timeout: 2, Valid In: 192.168.200.81/1 --> 192.168.200.207/2291;icmp, If: ge-0/0/4.0, Pkts: 1, Bytes: 84 Out: 10.80.80.87/2291 --> 192.168.200.81/1;icmp, If: ge-0/0/3.0, Pkts: 1, Bytes: 84 Total sessions: 1 [edit security nat] juniper@SRX#
So we have bidirectional traffic with only one rule. However, note that the static nat automatically installs a NAT session to allow bidirectional traffic, it only allows traffic to be initiated in the direction the NAT rule specifies. So if we try to match the session from the other side we get nothing:
ping from server to client
juniper@server:~$ ping -c 3 10.200.200.202 PING 10.200.200.202 (10.200.200.202) 56(84) bytes of data. From 10.80.80.1 icmp_seq=1 Destination Net Unreachable From 10.80.80.1 icmp_seq=2 Destination Net Unreachable From 10.80.80.1 icmp_seq=3 Destination Net Unreachable --- 10.200.200.202 ping statistics --- 3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2002ms juniper@server:~$
To make this work, you need a matching rule in the other direction as well.
SRX config for server to client traffic
[edit security nat] juniper@SRX# show static { rule-set STATIC-NAT-UNTRUST { from zone UNTRUST; rule STATIC-NAT-UNTRUST { match { source-address 192.168.200.80/29; destination-address 192.168.200.200/29; } then { static-nat { prefix { 10.80.80.80/29; } } } } } rule-set STATIC-NAT-TRUST { from zone TRUST; rule STATIC-NAT-TRUST { match { source-address 10.80.80.80/29; destination-address 10.80.80.200/29; } then { static-nat { prefix { 192.168.200.80/29; } } } } } } proxy-arp { interface ge-0/0/4.0 { address { 192.168.200.200/29; } } interface ge-0/0/3.0 { address { 10.80.80.200/29; } } } [edit security nat] juniper@SRX#
Once this is committed, it works.
ping from client to server
juniper@server:~$ ping -c 3 10.80.80.202 PING 10.80.80.202 (10.80.80.202) 56(84) bytes of data. 64 bytes from 10.80.80.202: icmp_req=1 ttl=63 time=2.86 ms 64 bytes from 10.80.80.202: icmp_req=2 ttl=63 time=3.07 ms 64 bytes from 10.80.80.202: icmp_req=3 ttl=63 time=2.26 ms --- 10.80.80.202 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2000ms rtt min/avg/max/mdev = 2.265/2.734/3.071/0.347 ms juniper@server:~$
Static NAT is always a 1:1 mapping. If you try to commit with the following config, where we're mapping a /29 to a /30 set of addresses, you get a commit error as seen by the bad configuration snippet below.
config without 1:1 mapping for static NAT generating a commit error
[edit security nat] juniper@SRX# show static { rule-set STATIC-NAT-UNTRUST { from zone UNTRUST; rule STATIC-NAT-UNTRUST { match { source-address 192.168.200.80/29; destination-address 192.168.200.200/29; } then { static-nat { prefix { 10.80.80.80/30; } } } } } } proxy-arp { interface ge-0/0/4.0 { address { 192.168.200.200/29; } } interface ge-0/0/3.0 { address { 10.80.80.200/29; } } } [edit security nat] juniper@SRX# commit error: Static NAT rule(STATIC-NAT-UNTRUST) error: host address doesn't have same mask as destination address. error: configuration check-out failed [edit security nat] juniper@SRX#