Tag Archives: freebsd

Simple FreeBSD Tunnels

It’s pretty easy in FreeBSD to create simple tunnels between two FreeBSD machines, between a FreeBSD machine and a Cisco router, or to any other host that supports the GRE interface.

The GRE (Generic Routing Encapsulation) interface (defined in RFC 1701 and 1702) has been included for a while, and provides a “standard” encapsulation protocol for tunneling.

So lets assume first a host-to-host tunnel:

Host A:

External IP: 192.168.10.1
Tunnel IP: 10.255.255.1/30
Internal Block: 10.10.0.1/24

Host B:

External IP: 192.168.20.1
Tunnel IP: 10.255.255.2/30
Internal Block: 10.20.0.1/24

Obviously, in a real-world situation, the “External IP” value in your setup, would likely be a real, valid, routable IP address. Also, I like to use a “stub” host block for the tunnel IP addresses- this is basically a block of four IP’s (/30, 2 usable), that are simply used to route either end of the tunnel.

Yes, you can use an IP in the internal block as the tunnel interface, which means you wouldn’t need the extra routes to route the local blocks, but this can break OSPF, so it’s just good (maybe?) practice to keep the two blocks separate.

First off, you need to make sure the gre interface type is available; your kernel should be compiled with:

device gre

or, if you’ve built all the modules as loadable, you can add:

if_gre_load="YES"

to your /boot/loader.conf; you can then either reboot, or run:

host> /sbin/kldload /boot/kernel/if_gre.ko

Which should load the module.

Next, you need to configure the interfaces on both machines; this assumes you don’t already have a greN interface setup- if you do, then just use the next logical number instead of 0.

On Host A:

ifconfig gre0 create
ifconfig gre0 10.255.255.1 10.255.255.2 netmask 255.255.255.252
ifconfig gre0 tunnel 192.168.10.1 192.168.20.1

On Host B:

ifconfig gre0 create
ifconfig gre0 10.255.255.2 10.255.255.1 netmask 255.255.255.252
ifconfig gre0 tunnel 192.168.20.1 192.168.10.1

You can run ifconfig gre0 on each host, and the interface should show as UP. You can also confirm it’s up by pinging the other end of the tunnel from each host; so from Host A, ping the 10.255.255.2 IP address (which is the remote end of the tunnel):

hosta> ping -c 3 10.255.255.2
64 bytes from 10.255.255.2: icmp_seq=0 ttl=64 time=43.192 ms
64 bytes from 10.255.255.2: icmp_seq=1 ttl=64 time=51.099 ms
64 bytes from 10.255.255.2: icmp_seq=2 ttl=64 time=51.459 ms

--- 10.255.255.2 ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 43.192/48.583/51.459/3.815 ms

Now you need to add routes for your internal blocks, so each end know to route over the tunnel:

On Host A:

route add 10.20.0.1/24 10.255.255.2

On Host B:

route add 10.10.0.1/24 10.255.255.1

Now don’t forget to add this config to your rc.conf files, so the interfaces get setup when the machines reboot:

On Host A:

cloned_interfaces="gre0"
ifconfig_gre0="inet 10.255.255.1 10.255.255.2 netmask 255.255.255.252 
tunnel 192.168.10.1 192.168.20.1"
static_routes="tunnel"
route_tunnel="10.20.0.1/24 10.255.255.2"

On Host B:

cloned_interfaces="gre0"
ifconfig_gre0="inet 10.255.255.2 10.255.255.1 netmask 255.255.255.252 
tunnel 192.168.20.1 192.168.10.1"
static_routes="tunnel"
route_tunnel="10.10.0.1/24 10.255.255.1"

(the ifconfig line was broken for display purposes; it should be one long line in you rc.conf file)

Now if your Host B in this scenario is not a FreeBSD box, but a Cisco device, the Cisco setup goes like this:

interface Tunnel0
  ip address 10.255.255.2 255.255.252
  tunnel mode gre
  tunnel source 192.168.20.1
  tunnel destination 192.168.10.1
!

ip route 10.10.0.1/24 255.255.255.0 10.255.255.2

Remember, this is just a simple encapsulation protocol, and not encryption- so data is not secure. Later, I’ll do an update which includes IPSEC on top of the GRE interface.