Showing posts with label firewall. Show all posts
Showing posts with label firewall. Show all posts

Monday, August 28, 2017

Cisco ASA -- Intro to NAT, Auto NAT and Twice NAT

A couple of years ago, I first started working with Cisco ASA firewalls. One of the things that has driven me nuts about the ASA is how complicated it makes NAT. From my experience with Linux, I was aware of Source NAT, Destination NAT and Masquerading. However, the ASA added several other variations on the theme: Single NAT, Auto NAT, Twice NAT, and most bizarre of all, Identity NAT. Cisco documentation and most other network references I consulted didn't clear things up much (if at all). Since I tend to learn best by being hands-on, I fired up GNS3 and started playing around with an emulated ASA.

First, single NAT. In this scenario, you manually create a NAT translation. In most cases, you have a private network using IP addresses defined in RFC-1918 on the inside of your firewall. Since this address space is not routable on the public Internet, you must rewrite the source address of any packet originating on your private network if you want to reach a host outside of your network. Likewise, if you have a server inside your private network that should be reachable from the Internet, incoming packets must have the destination IP address rewritten as they cross your firewall. This is pretty straightforward on the ASA. Given the following interface configuration...:

interface GigabitEthernet0.10
description INSIDE
vlan 10
nameif INSIDE
security-level 100
ip address 192.168.1.1 255.255.255.0
!
interface GigabitEthernet0.300
description OUTSIDE
vlan 300
nameif OUTSIDE
security-level 0
ip address 100.64.1.53 255.255.255.248
!

Next, we will define the client PC's "real" and "mapped" IP addresses (the IP address actually configured on the client, and the IP address that Internet hosts will see, respectively):

object network CLIENT
host 192.168.1.3
object network CLIENT-OUTSIDE
host 100.64.1.129

Finally, we create the NAT statement to translate the client's real IP to the mapped IP:

nat (INSIDE,OUTSIDE) source static CLIENT CLIENT-OUTSIDE

Now, when the client tries to reach a host on the public Internet, the firewall will rewrite incoming and outgoing packets as described above. To test this, I created a simple CGI script on a web server that displays the "environment variables" passed to the CGI in an HTTP session:



As you can see, the web server sees the client PC's IP address as 100.64.1.3 (okay, yes, technically, that is not a publicly routable IP address either, but is instead a "Carrier-grade NAT" address, a special private IP space address, but even in my labs in GNS-3, I don't like to use real public IP address space). Pretty simple, right?

Next up, Auto NAT (or Object-NAT, IIRC -- if I'm wrong, please leave a comment below!). Object-NAT looks very simple, and in many on-line tutorials I've seen, is described as one of the simplest ways of setting up NAT on a firewall. However, I have found it to be quite finicky, at least on the version of ASA code that I'm using in GNS3. More than once, I have copied an existing config, changing IP addresses and object names as required, but finding one config works while the other does not. Even more frustrating, the ASA code that I'm using in GNS3 is much older than the code I'm using in the real world, and the object-NAT configuration is slightly different between the two versions. Despite these differences, let's give object-NAT a try.

For the object-NAT example, we'll use the following network:



...and the following network objects:

1. The Knoppix Clone's real (RFC-1918) IP address:
object network CLONE-REAL-IP
host 192.168.1.2
!

2. The Knoppix Clone's NAT (i.e., "public") IP address:
object network CLONE-NAT-IP
host 100.64.1.2
!

3. The Knoppix Host's real (RFC-1918) IP address:
object network K32-REAL-IP
host 10.0.0.2
!

4. The Knoppix Host's NAT IP address:
object network K32-NAT-IP
host 100.64.0.2
!

The Knoppix Clone will be on our "inside" network, and Knoppix-32 will be on the "public" network. Yes, I know -- I am using private IP addresses for everything, but just play along, okay? ;) Auto-NAT is sometimes called Object-NAT because the NAT statement exists inside of an "object network ..." statement:
object network CLONE-NAT-IP
nat (Side_B,Side_A) nat (SIDE_B,SIDE_A) source dynamic CLONE-REAL-IP CLONE-NAT-IP
!

Just for giggles, try this after setting up the object NAT shown above:

sho run | begin CLONE-NAT-IP

Most likely, you saw something like this:

object network CLONE-NAT-IP
host 100.64.1.2
object network K32-REAL-IP
host 10.0.0.2
object network K32-NAT-IP
host 100.64.0.2
...

Wait a minute...what happened to our NAT statement? Well, if you keep scrolling, you'll see it somewhere down near the end of the config. For whatever reason, Cisco decided it made sense to break the object definition in two, putting the host (or subnet or range or...) portion in one place in the config and the NAT portion in another </shrug> Don't ask me; I don't know why, either.

In any case, now that the NAT rule has been created, let's try to ping the Knoppix Clone from the Knoppix Host:
        Side_A pings Side_B:
        ping 100.64.1.2

        Side_A tcpdump:
          10.0.0.2 > 100.64.1.2
          10.0.0.2 > 100.64.1.2

        Side_B tcpdump:
...nothing...

Next, we'll try pinging from the Knoppix Clone to the Knoppix Host:
        Side_B pings Side_A:
        ping 10.0.0.2

        Side_A tcpdump:
          100.64.1.2 > 10.0.0.2
          10.0.0.2 > 100.64.1.2

        Side_B tcpdump:
          192.168.1.2 > 10.0.0.2
          10.0.0.2 > 192.168.1.2

Did that make sense? Because this NAT translation only allows traffic to originate on the inside network (established, related packets will always be allowed back in with a stateful firewall), the Knoppix Host cannot ping the Knoppix Clone, but the Knoppix Clone can ping the Knoppix Host.

Things really get interesting, however, with Twice NAT. In this situation, not only do you want to rewrite the IP address of a system on the INSIDE network, but you also want to rewrite the IP address of a system on the OUTSIDE network as well. Why? Well...I don't know. But if for some reason you do, here's how to do it :)

We'll use the same ASA interface configuration that we used in the discussion of Single NAT above.

Next, we'll define the objects used in this config. As in the Single NAT and Auto NAT discussion, we'll use "CLIENT" to mean the host on the inside network and "CLIENT-OUTSIDE" to mean the NAT'd IP address of the client host (the IP that outside hosts see the request coming from). However, we will create two new objects, "MAPPED-DEST" which is the IP address that CLIENT will use in URL's, ping commands, etc. and "REAL-DEST" which is the actual IP address of the host on the OUTSIDE network. In other words, just as "CLIENT" refers to the actual IP address configured on the host on the INSIDE network, "REAL-DEST" refers to the actual IP address configured on host on the OUTSIDE network. Likewise, just like "CLIENT-OUTSIDE"refers to the IP address that OUTSIDE hosts use to reach the INSIDE network, "MAPPED-DEST" refers to the IP address that INSIDE hosts use to reach the OUTSIDE network:

object network MAPPED-DEST
host 172.16.0.1
object network REAL-DEST
host 100.64.1.3

Finally, we create the NAT statement to set up the Twice NAT:

nat (INSIDE,OUTSIDE) source static CLIENT CLIENT-OUTSIDE destination static MAPPED-DEST REAL-DEST

The only difference between this config and the Single NAT config is the addition of "destination static MAPPED-DEST REAL-DEST" at the end of the NAT statement. On the CLIENT computer, we can now try to access the server on the OUTSIDE network using the IP address 172.16.0.1:


As you can see, we are accessing the web server on the outside network by using the IP address 172.16.0.1, even though the IP address on the server is actually 100.64.1.3. Likewise, the web server sees the request coming from 100.64.1.129, even though the client's IP address is actually 192.168.1.3. In other words, we are NAT'ing both the INSIDE and OUTSIDE networks.

For our last example, we'll set up identity-NAT. I have to admit, this twist on NAT really threw me when I first encountered it. "Wait, you mean to tell me that we are creating a NAT rule to rewrite an incoming packet to use the EXACT SAME IP address it originally had?!?!" At first, it does seem a little silly, doesn't it? However, consider this scenario: you have a firewall with an inside and outside network, and you have an object-NAT rule to translate outgoing requests to a pool of publicly routable IP addresses. However, for some reason, there is a host or subnet connected to your outside interface that you wish to access via your private, inside IP addresses. For example, it is possible that in a large enterprise network, you might have firewalls between various departments inside the company. These firewalls might do the NAT translations from RFC-1918 addressing to public addressing, but you might still want to access a resource in another department via your private IP range (that's kinda-sorta the situation with one of the ASA's I currently manage). In this case, the identity-NAT rule will override the object-NAT rule for the objects that you specify. In terms of configuring identity-NAT, it's pretty much the same as single-NAT, except that you use the same source object and destination object in the NAT rule:

object network CLIENT
host 192.168.1.3
object network CLIENT-OUTSIDE
host 100.64.1.129
!
nat (INSIDE,OUTSIDE) source static CLIENT CLIENT

No, that's not a typo -- I really did mean "CLIENT CLIENT" in the NAT rule. Essentially, we are saying, "When a packet comes into the INSIDE interface with the IP address 192.168.1.3, rewrite the packet exiting the OUTSIDE interface with the source IP address of 192.168.1.3. This works because the ASA follows a hierarchy much like the mathematical concept of "order of operations" to determine at what point the various types of NAT will be performed. In this case, the identity NAT will happen after the object-NAT, so the identity-NAT rule will override the object-NAT.

Thursday, November 14, 2013

JNCIA Lesson 4 1/2 -- More on Routing Policies and Firewall Filtering

One of the concepts that I have struggled with the most while trying to learn JunOS is the filtering language used on Juniper devices. That's a pretty significant problem too, because the filtering language is basically a core feature of JunOS, cropping up in Class of Service/Quality of Service, routing policies, and, of course, basic firewall/security on JunOS devices. It's pretty safe to say that if you don't understand this core concept, you will not be proficient in JunOS, and therefore, I decided I needed to spend a little while playing with the filtering syntax so I can understand it better. In it's most basic form, the filtering rules follow the pattern, "match-action" -- that is, you define a pattern to match, then upon a match, you perform some action on incoming packets -- and then you apply the filter to an interface or VLAN. There are three important concepts to keep in mind when trying to compose a filter rule:
  1. Within a single term, match rules are logical-AND'ed together. That is, if you put a rule to match a source IP address inside a term, then put a second rule to match a destination port, the filter will only match packets from that particular source IP address AND to that particular destination port (i.e., from 192.168.1.17, to port 23). If you want to logically OR rules, you have to create separate terms in the firewall rule-set;
  2. Packets are compared to each term from the top down, and the firewall stops comparing the packet to the firewall rules when it finds a match. In other words, if you put an "allow any" rule as the first term in your match rules, then put specific "deny ..." rules below, all packets will match against the "allow any" and no packet will ever be compared against the "deny ..." rules;
  3. There is an implicit "deny all" at the very end of the firewall rules, even though it is not shown in the configuration. Therefore, you must always make sure that you include rules to match all of the traffic that you want to allow. For example, suppose you are seeing brute-force password guessing attacks through SSH from the IP address 1.2.3.4, so you create a rule to drop traffic matching the source address of 1.2.3.4 and destination port 22. Unless you configure a rule to allow everything else, the implicit "deny all" rule will drop all traffic coming in on the interface or VLAN to which you applied the firewall rule.


Let's start with a simple example: suppose I have a switch on the 192.168.1.0/24 network, I have a host at 192.168.1.1, and on my switch, I want to block ICMP messages from that host with an "ICMP Administratively Prohibited" notification, while allowing any other protocol from 192.168.1.1 or all traffic from other source addresses.

root@branch-3200# set firewall family inet filter no-icmp term drop-icmp from source-address 192.168.1.1

[edit]
root@branch-3200# set firewall family inet filter no-icmp term drop-icmp from protocol icmp

[edit]
root@branch-3200# set firewall family inet filter no-icmp term drop-icmp then reject administratively-prohibited

[edit]
root@branch-3200# commit
commit complete

[edit]
root@branch-3200#


If we attempt to ping 192.168.1.2 (the EX3200 switch) from 192.168.1.1 at this point, we will find the firewall isn't particularly effective:

root@main3200> ping 192.168.1.2
PING 192.168.1.2 (192.168.1.2): 56 data bytes
64 bytes from 192.168.1.2: icmp_seq=0 ttl=64 time=3.630 ms
64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=2.408 ms
64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=2.395 ms
^C
--- 192.168.1.2 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 2.395/2.811/3.630/0.579 ms

root@main3200>


Since we haven't applied the firewall to an interface or VLAN yet, no incoming packets are being compared against the firewall rules, and therefore all inbound traffic is still allowed. Let's take care of that, now:

root@branch-3200# set interfaces vlan unit 0 family inet filter input no-icmp

[edit]
root@branch-3200# commit
commit complete

[edit]
root@branch-3200#


To create our firewall, we started by adding a rule that drops traffic only if the source address is 192.168.1.1. However, we only want to drop ICMP traffic, so we then added a second rule (with the same term name, namely "drop-icmp") that drops ICMP traffic. Since the terms are cumulative, we've essentially created a rule that says, "if the source address matches 192.168.1.1 AND the protocol is ICMP..." Then, we created an action to reject matching packets with the "administratively prohibited" message. Let's see how it works:

root@main3200> ping 192.168.1.2
PING 192.168.1.2 (192.168.1.2): 56 data bytes
36 bytes from 192.168.1.2: Communication prohibited by filter
Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst
4  5  00 0054 d4e0   0 0000  40  01 2275 192.168.1.1  192.168.1.2
<...snip...>
^C
--- 192.168.1.2 ping statistics ---
3 packets transmitted, 0 packets received, 100% packet loss
root@main3200>


Good, good...

root@main3200> telnet 192.168.1.2
Trying 192.168.1.2...
telnet: connect to address 192.168.1.2: Operation timed out
telnet: Unable to connect to remote host

root@main3200>


Hrmmm...Well, we're half-way there. We are successfully blocking ICMP, but apparently, we are also blocking telnet. Remember, JunOS adds an implicit "deny all" at the end of the firewall rules. Since we create a rule to block ICMP from 192.168.1.1, but we didn't include a rule to allow any packets, we are actually blocking ALL packets on vlan.0. To fix this, we have to add a new term to allow anything that isn't ICMP and from 192.168.1.1:

root@branch-3200# set firewall family inet filter no-icmp term everything-else source 0.0.0.0/0

[edit]
root@branch-3200# set firewall family inet filter no-icmp term everything-else then accept

[edit]
root@branch-3200# commit
commit complete

[edit]
root@branch-3200#


Let's see if that solves the problem:

root@main3200> ping 192.168.1.2
PING 192.168.1.2 (192.168.1.2): 56 data bytes
36 bytes from 192.168.1.2: Communication prohibited by filter
Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst
4  5  00 0054 2f4c   0 0000  40  01 c809 192.168.1.1  192.168.1.2

36 bytes from 192.168.1.2: Communication prohibited by filter
Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst
4  5  00 0054 2f76   0 0000  40  01 c7df 192.168.1.1  192.168.1.2

36 bytes from 192.168.1.2: Communication prohibited by filter
Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst
4  5  00 0054 2f9c   0 0000  40  01 c7b9 192.168.1.1  192.168.1.2

^C
--- 192.168.1.2 ping statistics ---
3 packets transmitted, 0 packets received, 100% packet loss

root@main3200> telnet 192.168.1.2
Trying 192.168.1.2...
Connected to 192.168.1.2.
Escape character is '^]'.

branch-3200 (ttyp0)

login:
telnet> quit
Connection closed.

root@main3200>


That's more better :) We are now successfully blocking ICMP from 192.168.1.1 while still allowing other protocols, such as TCP/23 (telnet) to the switch.

However, looking at the firewall rules, something doesn't seem to be right. We have two rules to block source-address 192.168.1.1 and protocol ICMP, but the allow rule only specifies a source-address. How does this rule work?

Keep in mind that JunOS firewall rules work from top down, and they stop looking for matches as soon as a packet matches a term. Consequently, any packet originating from 192.168.1.1 and using the ICMP protocol matches our "reject ..." rule. However, if the packet comes from another source address or is a protocol other than ICMP, JunOS continues comparing the packet with the firewall rules. Therefore, anything not matching the "drop-icmp" term is compared to the "everything-else" term. The "everything-else" term tries to match the packet against the source-address of 0.0.0.0/0 -- in other words, against all possible source IP addresses. Since this second term will match a packet coming from any IP address, it is essentially an "allow any" rule. Therefore, our rule effectively reads, "if the packet matches 192.168.1.1 and matches the ICMP protocol, then reject it with the 'administratively-prohibited' message. If it is anything else, allow it."

Monday, November 11, 2013

JNCIA Lesson 4 -- Routing Policies and Firewall Filters

There's a particularly corny scene in the movie "Firewall" where Harrison Ford's character takes over for a junior network admin when the bank he works for is being DoS'd -- or maybe it was just a brute-force password guessing attack, I can't remember now -- by an outside attacker. Peering intently at the screen, Ford thinks for a minute, then pecks out a sequence of commands on the screen, finishing with a smug, "That should hold them up for a while," to which the junior admin replies, "It would hold me up!" What makes the scene corny is that they catch just a second of the monitor on-camera, and I could see that Ford (or more likely, their technical consultant) had typed a simple Cisco access control list to block traffic from a specific source IP address. Any competent network admin can tell you that a serious attacker could easily repeat the attack from another address, and another, and another, ad infinitum, until the increasingly complex access control list alone causes as much trouble as the initial attack.

However, ACL's -- or Juniper's even more flexible and powerful firewall filters -- have a valid role in network security, and on JunOS, they provide for an even more mundane -- yet essential -- role in configuring dynamic routing. Let me start with a simple example: suppose you have a router at your main office location, with two branch offices connected through a private network provided by your service provider (Metro-Ethernet service, for example). You have multiple VLANs on each router which must be able to communicate with each VLAN on the other routers. The main office router has a single Internet connection to your upstream service provider. You want each of the branch office routers to be able to connect to the Internet through your main office router. When finished, the network should look something like this:



In the last lesson, we configured a simple network using OSPF to route between three LAN networks. This time, however, we have added a fourth route to our ISP. Generally, a small or even medium sized business doesn't share routes with their ISP. The ISP doesn't care about routes to your internal network (that's why RFC-1918 was created in the first place), nor does a typical small office router have enough memory or processing power to store the entire Internet's routing table (especially not if using RIP or OSPF, but that's a whole other topic we won't get into now). In fact, if you only have a single connection to your ISP, this is a perfect use for a static route. Router A, which is the only router connected to the upstream service provider, will have a static, default route. If only there were a way to share that route with routers B and C...

On a Cisco router, this would be a piece of cake: you would simply create the default route, then use the "default-information originate" command to tell OSPF to distribute the default route in your OSPF area. On a Juniper, it is (IMHO) more complicated than it needs to be, but it's not really THAT bad. First, just like a Cisco, we'll create the default route:

root@main3200# top

[edit]
root@main3200# set routing-options static route 0.0.0.0/0 next-hop 100.64.170.65

[edit]
root@main3200#


At this point, you should be able to ping onto the Internet (or to a test network beyond the "ISP" router) from Router A. However, from Router B or Router C, there is still no default route defined:

root@branch2-3200# run show route 172.16.0.1

[edit protocols ospf]
root@branch2-3200#


Next, we have to define a routing policy to redistribute this route into OSPF...:

root@main3200# set policy-options policy-statement ospf-default term 1 from route-filter 0.0.0.0/0 exact accept

[edit]
root@main3200#


...and then export that filter into OSPF:

root@main3200# set protocols ospf export ospf-default

[edit]
root@main3200# commit
commit complete

[edit]
root@main3200#


If you try again from Router C...:

root@branch2-3200# run show route 172.16.0.1

inet.0: 10 destinations, 10 routes (10 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

0.0.0.0/0          *[OSPF/150] 00:01:16, metric 0, tag 0
                    > to 10.11.12.1 via ge-0/0/21.0

[edit protocols ospf]
root@branch2-3200#


Success!!! However, if you're like I was when I first figured this out, you are probably going, "That's the stupidest, most convoluted thing..."

Yeah, I get it, and I don't entirely disagree. Cisco and pretty much everyone else who makes the network gear that I've played with in the past assume that you *want* to share routes (that's what a router is for, after all, right?), and so their default policy is exactly that: when you enable a dynamic routing protocol, it's going to start advertising all the routes it can find, or at the very least, there will be switches ("default-information originate," "redistribute connected," "redistribute static," etc.) that turn on very broad swathes of networks with a single command. However, in such cases, it can be very easy to share more information than you intended, and in fact, can be rather difficult to filter out some of the networks that you don't want to share. JunOS, on the other hand, takes the exact opposite approach, and only shares routes that you explicitly tell the router that you want to share. From a security standpoint, I'd have to say the Juniper approach might -- just maybe -- be the better choice. And honestly, their filtering language is much more flexible and powerful than Cisco's ACL's, IMHO. So, enough with the sales pitch; let's dissect those commands and try to figure out exactly what they mean.

The first command we used was "set routing-options static route 0.0.0.0/0 next-hop 100.64.170.65" which is essentially telling the router, "if you don't know what route to take to reach a destination address, just send it to our default gateway at 100.64.170.65."

The last command was "set protocols ospf export ospf-default" which was telling the router that we want to export the routes defined in a route filter that we named "ospf-default" into our OSPF routing protocol. Again, pretty simple and straightforward.

The magic all happens in the second command, "set policy-options policy-statement ospf-default term 1 from route-filter 0.0.0.0/0 exact accept." There's a lot happening in this command, so let's dissect it a little further. In the first half, "set policy-options policy-statement ospf-default..." we are telling the router that we are going to create a filter, and that we want to name the filter "ospf-default." Next, we define the filter. A filter in JunOS can be a sequence of match-action statements, which is roughly analogous to "if-then" statements in a programming language. You can chain multiple statements together in JunOS to create complex, compound statements, just like you would in a programming language. We want to match basically any destination address, so the pseudo-code for what we want to accomplish looks more or less like this:

if destination-address matches 0.0.0.0/0 then
  forward the packet through the static route that matches the destination 0.0.0.0/0


Okay, that seems easy enough. What if we want to route anything matching 172.16.10.0/24 to one router, and route anything else to a second router? Let's try it. First, we'll configure a physical interface through which we will forward traffic:

root@main3200# set interfaces ge-0/0/19 unit 0 family ethernet-switching

[edit]
root@main3200# set interfaces ge-0/0/19 unit 0 family inet address 100.64.5.2/26

[edit]
root@main3200# show interfaces ge-0/0/19
unit 0 {
    family inet {
        address 100.64.5.2/26;
    }
}

[edit]
root@main3200# commit
commit complete

[edit]
root@main3200#


I have connected a router to ge-0/0/19 on Router A to simulate another remote network (172.16.10.0/24) and connected a remote host on the outside interface of this router, using the IP address 172.16.10.20. On the outside interface of our "Internet" router, connected to ge-0/0/20, I have connected a host using the IP address 172.16.20.237. Connected to branch1-3200, I have a host using the IP address 192.168.2.32, and connected to branch1-3200, I have a host using the IP address 192.168.3.32. Right now, the two 192.168.x.32 hosts can ping each other, and the 172.16.20.237 host:

root@branch2-host1:~# ip addr | egrep -A3 eth0 | egrep "(eth0|inet) "
    inet 192.168.3.32/24 brd 192.168.3.255 scope global eth0
    inet 172.16.0.58/30 brd 172.16.0.59 scope global eth0.21
root@branch2-host1:~# ping -c1 192.168.2.32
PING 192.168.2.32 (192.168.2.32) 56(84) bytes of data.
64 bytes from 192.168.2.32: icmp_req=1 ttl=62 time=5.16 ms

--- 192.168.2.32 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 5.163/5.163/5.163/0.000 ms
root@branch2-host1:~# ping -c1 172.16.20.237
PING 172.16.20.237 (172.16.20.237) 56(84) bytes of data.
64 bytes from 172.16.20.237: icmp_req=1 ttl=61 time=1.34 ms

--- 172.16.20.237 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.342/1.342/1.342/0.000 ms
root@branch2-host1:~#


...and...:

me@branch1-host1:~$ ip addr | egrep eth0 | egrep "(eth0|inet) "
    inet 192.168.2.32/24 brd 192.168.2.255 scope global eth0
me@branch1-host1:~$ ping -c1 192.168.3.32
PING 192.168.3.32 (192.168.3.32) 56(84) bytes of data.
64 bytes from 192.168.3.32: icmp_req=1 ttl=62 time=2.93 ms

--- 192.168.3.32 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 2.936/2.936/2.936/0.000 ms
me@branch1-host1:~$ ping -c1 172.16.20.237
PING 172.16.20.237 (172.16.20.237) 56(84) bytes of data.
64 bytes from 172.16.20.237: icmp_req=1 ttl=61 time=1.51 ms

--- 172.16.20.237 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.510/1.510/1.510/0.000 ms
me@branch1-host1:~$


However, as of yet, there is no path to the host at 172.16.10.20:

root@branch2-host1:~# ping -c1 172.16.10.20
PING 172.16.10.20 (172.16.10.20) 56(84) bytes of data.
From 100.64.170.79 icmp_seq=1 Time to live exceeded

--- 172.16.10.20 ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms

root@branch2-host1:~#


...and...:

me@branch1-host1:~$ ping -c1 172.16.10.20
PING 172.16.10.20 (172.16.10.20) 56(84) bytes of data.
From 100.64.170.79 icmp_seq=1 Time to live exceeded

--- 172.16.10.20 ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms

me@branch1-host1:~$


This is expected, since we currently have a default route, redistributed through OSPF, from the main office router to both branch office routers. We now need to create a second route on the main office router to match 172.16.10.0/24, and redistribute it through OSPF to the branch office routers:

root@main3200# set routing-options static route 172.16.10.0/24 next-hop 100.64.5.1

[edit]
root@main3200# set policy-options policy-statement ospf-default term 2 from route-filter 172.16.10.0/24 exact accept

[edit]
root@main3200# set protocols ospf export ospf-default

[edit]
root@main3200#


We also need to tell the two branch routers how to reach the next-hop address of 100.64.5.1:

root@main3200# set protocols ospf area 0.0.0.0 interface ge-0/0/19.0 passive

[edit]
root@main3200# commit
commit complete

[edit]
root@main3200#


...and now we have both a default route through the "ISP" through ge-0/0/20 and to the host on 172.16.10.20 through ge-0/0/19, shared with all three office locations.