Have you ever found yourself unable to connect to specific VPNs due to firewalls or censorship devices that block your connection to outside networks? It can be frustrating, but there’s a solution: routing your traffic through a trusted network that you can access.

Here’s the problem: you may have access to a trusted network, but it doesn’t have direct access to the outside world. This means that you need to create an intermediate VPN that allows you to connect to the outside world from within the trusted network.

One way to set up this intermediate VPN is by using FreeBSD Jails with multiple FIBs. With this setup, you have full control over the traffic and can access multiple VPNs at the same time.

Here’s how it works: first, you establish a VPN connection from your laptop to the trusted network, which is your intermediate VPN. Then, using FreeBSD Jails with multiple FIBs, you can establish additional VPN connections from your intermediate VPN to multiple VPN endpoints. This allows you to bypass censorship and connect to VPNs that were previously inaccessible.

Using FreeBSD Jails with multiple FIBs is a powerful solution for those who need to access restricted networks. With this setup, you can have full control over your traffic and access multiple VPNs simultaneously.

In this blog post, I’m going to share my current network configuration. I’m going to break down my configuration step by step and explain each component in detail.

Documentation

  • fib 0: without VPN

      * vtnet0: 1.1.1.2/24
      * e0a_overlay: 172.31.87.1/30
    
  • fib 1: with VPN

      * e1a_overlay: 172.31.88.1/30
      * tun257: openvpn-client 172.31.1.174 -> 173
    
  • jail:

      * e0b_overlay: 172.31.87.2/30
      * e1b_overlay: 172.31.88.2/30
      * ocserv clients: 172.31.5.0/24
    

Firstly, my network consists of two FIBs: one without VPN and one with VPN. For the first FIB, I use the vtnet0 interface with IP address 1.1.1.2/24, while for the second FIB, I use the tun257 interface with IP address 172.31.1.174 -> 173. The VPN is established through OpenVPN, and the IP addresses for the VPN connections are 172.31.87.1/30 for e0a_overlay, and 172.31.88.1/30 for e1a_overlay.

rc.conf

Replace ip addresses and interface names to your own environment. Add these to your /etc/rc.conf configurations:

ifconfig_vtnet0="inet 1.1.1.2/24 -tso -rxcsum"
defaultrouter="1.1.1.1"
cloned_interfaces="tun257 epair1 epair0"
ifconfig_epair0a="name e0a_overlay -tso -rxcsum"
ifconfig_epair0b="name e0b_overlay -tso -rxcsum"
ifconfig_epair1a="name e1a_overlay fib 1 -tso -rxcsum"
ifconfig_epair1b="name e1b_overlay fib 1 -tso -rxcsum"
ifconfig_tun257="fib 1 -tso -rxcsum"
pf_enable="YES"
pflog_enable="YES"
ezjail_enable="YES"
gateway_enable="YES"
static_routes="outsidevpn defaultfib1"
route_outsidevpn="-net 2.2.2.2 -gateway 1.1.1.1 -fib 1"
route_defaultfib1="-net default -gateway 1.1.1.1 -fib 1"
openvpn_outsidevpn_enable="YES"
openvpn_outsidevpn_fib="1"
openvpn_outsidevpn_configfile="/usr/local/etc/openvpn/outsidevpn.conf"

Next, let’s take a look at the rc.conf file. Here, we specify the configuration for our interfaces and the routing table. We enable the PF firewall and configure static routes for traffic to 2.2.2.2 which is our final vpn ip address. We also enable OpenVPN for outsidevpn, specifying that it uses FIB 1, and we provide the path to the OpenVPN configuration file.

(Jail) rc.conf

/usr/jails/overlay/etc/rc.conf:

ifconfig_e0b_overlay="inet 172.31.87.2/30 fib 0"
ifconfig_e1b_overlay="inet 172.31.88.2/30 fib 0"
defaultrouter="172.31.88.1"
ocserv_enable="YES"
gateway_enable="YES"

ezjail/jail configuration

Use the configuration below if you use ezjail for jail management.

export jail_overlay_hostname="overlay"
export jail_overlay_ip=""
export jail_overlay_rootdir="/usr/jails/overlay"
export jail_overlay_exec_start="/bin/sh /etc/rc"
export jail_overlay_exec_stop=""
export jail_overlay_mount_enable="YES"
export jail_overlay_devfs_enable="YES"
export jail_overlay_devfs_ruleset="6"
export jail_overlay_procfs_enable="YES"
export jail_overlay_fdescfs_enable="YES"
export jail_overlay_image=""
export jail_overlay_imagetype="zfs"
export jail_overlay_attachparams=""
export jail_overlay_attachblocking=""
export jail_overlay_forceblocking=""
export jail_overlay_zfs_datasets=""
export jail_overlay_cpuset=""
export jail_overlay_fib=""
export jail_overlay_parentzfs="zroot/jails"
export jail_overlay_parameters=""
export jail_overlay_post_start_script=""
export jail_overlay_retention_policy=""
export jail_overlay_vnet_enable="YES"
export jail_overlay_vnet_interface="e0b_overlay e1b_overlay"
export jail_overlay_exec_prestart0="/sbin/ifconfig e0a_overlay inet 172.31.87.1/30"
export jail_overlay_exec_prestart1="/sbin/ifconfig e1a_overlay inet 172.31.88.1/30"
export jail_overlay_exec_prestart2="/sbin/route add -net 172.31.5.0/24 -gateway 172.31.88.2 -fib 1"
export jail_overlay_exec_prestart3="/sbin/route add -net 172.31.5.0/24 -gateway 172.31.87.2"
export jail_overlay_exec_poststop0="/sbin/route del -net 172.31.5.0/24 -gateway 172.31.87.2"
export jail_overlay_exec_poststop1="/sbin/route del -net 172.31.5.0/24 -gateway 172.31.88.2 -fib 1"
export jail_overlay_exec_poststop2="/sbin/ifconfig e0a_overlay delete"
export jail_overlay_exec_poststop3="/sbin/ifconfig e1a_overlay delete"

Moving on to the jail configuration, we define several environment variables that specify the configuration for our jail. The jail_overlay_hostname specifies the hostname of the jail, while jail_overlay_ip is left empty because we use VNET to assign an IP address to the jail. We specify the root directory for the jail, as well as the startup and shutdown scripts. We enable various filesystems and attach the jail to a ZFS dataset. We also enable the VNET feature and specify the interfaces that the jail uses.


(Jail) ocserv.conf

auth = "plain[passwd=/usr/local/etc/ocserv/auth.passwd]"
listen-host = 172.31.87.2
udp-listen-host = 172.31.87.2
tcp-port = 1435
udp-port = 1435
run-as-user = _ocserv
run-as-group = _ocserv
socket-file = /var/run/ocserv-socket
server-cert = /usr/local/etc/ocserv/fullchain.pem
server-key = /usr/local/etc/ocserv/privkey.pem
dh-params = /usr/local/etc/ocserv/dh.pem
ca-cert = /usr/local/etc/ocserv/ca.pem
banner = "It's Pouria, Welcome. All Clients Have 2 Concurrent Limitation."
max-clients = 32
max-same-clients = 2
rate-limit-ms = 100
server-stats-reset-time = 604800
keepalive = 32400
dpd = 90
mobile-dpd = 1800
switch-to-tcp-timeout = 25
try-mtu-discovery = true
cert-user-oid = 0.9.2342.19200300.100.1.1
tls-priorities = "NORMAL:%SERVER_PRECEDENCE:%COMPAT:-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1"
auth-timeout = 240
min-reauth-time = 300
max-ban-score = 80
ban-reset-time = 1200
cookie-timeout = 300
deny-roaming = false
rekey-time = 172800
rekey-method = ssl
use-occtl = true
pid-file = /var/run/ocserv.pid
log-level = 1
device = tun
predictable-ips = true
default-domain = overlay.spmzt.net
ipv4-network = 172.31.5.0
ipv4-netmask = 255.255.255.0
tunnel-all-dns = true
dns = 9.9.9.9
dns = 1.1.1.1
ping-leases = false
route = default
cisco-client-compat = true
dtls-legacy = true
client-bypass-protocol = false

I also have a jail, which has two interfaces, e0b_overlay and e1b_overlay, with IP addresses 172.31.87.2/30 and 172.31.88.2/30, respectively. This jail serves as an ocserv server, and all clients of ocserv have IP addresses in the range 172.31.5.0/24.

We take a look at the ocserv.conf file, which specifies the configuration for the ocserv server. Here, we define the authentication method and the port numbers for the TCP and UDP protocols. We also specify the server certificate and key, the Diffie-Hellman parameters, and the CA certificate.


pf.conf

set skip on { lo0 }

scrub in on vtnet0 all

nat pass on vtnet0 from 172.31.5.0/24 to any -> 1.1.1.2
nat pass on vtnet0 from 172.31.87.0/30 to any -> 1.1.1.2

nat pass on tun257 from 172.31.5.0/24 to any rtable 1 -> ( tun257 )
nat pass on tun257 from 172.31.88.0/30 to any rtable 1 -> ( tun257 )

rdr pass on vtnet0 inet proto tcp from any to 1.1.1.2 port = 1435 -> 172.31.87.2
rdr pass on vtnet0 inet proto udp from any to 1.1.1.2 port = 1435 -> 172.31.87.2

antispoof quick for vtnet0

block all

pass out on vtnet0 all
pass out on vtnet0 all rtable 1

pass log on e0a_overlay
pass log on e1a_overlay rtable 1

pass on tun257 all rtable 1
pass in on vtnet0 all

This is a configuration file for pf (Packet Filter), a firewall software for OpenBSD and other BSD-based operating systems.

The first line skips the firewall rules for the loopback interface.

The “scrub” line enables packet scrubbing on the “vtnet0” interface, which helps prevent certain types of attacks.

The next two “nat” lines perform network address translation (NAT) on traffic going out of the “vtnet0” interface, translating the source IP addresses from either the 172.31.5.0/24 or 172.31.87.0/30 network to 1.1.1.2.

The two “nat” lines that follow perform similar NAT functions for traffic going out of the “tun257” interface.

The two “rdr” lines redirect incoming TCP and UDP traffic destined for 1.1.1.2 on the “vtnet0” interface to 172.31.87.2.

The “antispoof” line enables antispoofing for the “vtnet0” interface, which helps prevent IP spoofing attacks.

The “block all” line blocks all traffic that is not specifically allowed by other rules.

The “pass out” lines allow all outgoing traffic on the “vtnet0” interface and also allow traffic from that interface with an associated routing table called “rtable 1”.

The two “pass log” lines allow traffic through two overlay interfaces called “e0a_overlay” and “e1a_overlay”, respectively.

The last two lines allow all traffic on the “tun257” interface and allow all incoming traffic on the “vtnet0” interface.


In the sysctl.conf file, we set net.add_addr_allfibs to 1.

sysctl.conf

net.add_addr_allfibs=1
net.fibs=2

Apply sysctl configurations

sysctl -f /etc/sysctl.conf

/etc/devfs.rules

[devfsrules_jail_vnet_tun=6]
add include $devfsrules_hide_all
add include $devfsrules_unhide_basic
add include $devfsrules_unhide_login
add include $devfsrules_jail
add include $devfsrules_jail_vnet
add path 'tun*' unhide

The code you provided is a configuration file for devfs, which is the device file system used in FreeBSD operating system. The file is called devfs.conf and it contains a set of rules that specify how devices are accessed and managed.

The first line in the file sets the rule for a jail that has Virtual Network Interface Card (VNET) and a Tunnel interface (TUN) with the number 6. The following lines include other rules that hide or unhide various types of devices, such as basic devices, login devices, and jail devices. The final line in the file specifies that any device path that starts with “tun” should be unhidden, meaning it can be accessed by the jail.

Overall, this configuration allows me to maintain a secure and reliable network, with multiple FIBs and a jail that serves as an ocserv server. I hope this breakdown of my configuration has been helpful to you.