# Force a jail to use OpenVPN tunnel



## spork (Jul 16, 2018)

So I have a few questions about how to best do this...  I have an OpenVPN client on a host and I would like a jail on that host to use that tunnel for all non-local access.  I also need to reach this jail from other hosts on the same subnet.  The host/jail are behind a firewall, so no firewalling or NAT are happening on the host.

I found this post describing a way to do this, and in theory, this basically works:

https://blog.feld.me/posts/2015/06/routing-a-freebsd-jail-through-openvpn/

What I'm struggling with here though is that the above config relies on setting a static IP in jail.conf.  The provider at the other end of my VPN allocates that IP dynamically.  The current jail.conf configuration style does not seem to allow the "ineherit" option for an IP address, nor offer a way to limit "inherit" to a particular interface (in this case tun0).

Are there any workarounds here to replicate the "inherit" behavior?  It's the only way I can see to deal with an interface whose address may change without restarting the jail...

Any other ideas?  I've seen people mention running OpenVPN inside a jail, I suspect using "VIMAGE", but I'm not certain whether VIMAGE is currently stable or production-ready.


----------



## Chris_H (Jul 17, 2018)

OK spork I know _exactly_ how to do this. This is often how I setup my jail(8)s (minus vpn). But that's incidental. Before I explain how I do it. I see you indicated you use ezjail, in another thread. Is this ezjail, of a conventional jail?

--Chris


----------



## spork (Jul 17, 2018)

Using "jail.conf" method here, first time I'm actually playing around with that before I attempt it at work.


----------



## Chris_H (Jul 17, 2018)

spork said:


> Using "jail.conf" method here, first time I'm actually playing around with that before I attempt it at work.


Good for you, spork ! Good choice. 
OK then
Basically, you're just going to clone your loopback device, and route your traffic through lo1
You'll also want (need) to use pf(4).
Here goes:
rc.conf(5)

```
pf_enable="YES"
pflog_enable="YES"

cloned_interfaces="lo1"

jail_enable="YES"

jail_list="<your_jail_name_here>"
```

jail.conf(5):

```
your-jail-name {
path = /path/to/your/jail;
host.hostname = your-jail-name.localhost;
ip4.addr = 127.0.0.2;
interface = lo1;
#jid = 1;
exec.clean;
mount.devfs;
mount.fdescfs;
mount.procfs;
exec.start =    "/bin/sh /etc/rc";
exec.stop = "/bin/sh    /etc/rc.shutdown";
exec.consolelog = /var/log/jail.your-jail-name.console.log;
}
```
pf.conf(5):

```
EXT_ADDR="<your-internet-IP-here>"

...

set skip on { lo0 }

...

nat pass on <your-nic-device-name-here> from lo1 to any -> $EXT_ADDR
rdr pass on <your-nic-device-name-here> proto tcp from any to lo1 -> $EXT_ADDR
```

That is the basics of it.

HTH

--Chris


----------



## spork (Jul 17, 2018)

Hmmm...  I don't think that's going to help with my situation.  What I really need is to figure out how to get the jail() "inherit" value set.

From the manpage:


```
ip4       Control the availability of IPv4 addresses.  Possible values are
             ``inherit'' to allow unrestricted access to all system addresses,
             ``new'' to restrict addresses via ip4.addr, and ``disable'' to
             stop the jail from using IPv4 entirely.  Setting the ip4.addr
             parameter implies a value of ``new''.
```

Basically, I need to get "tun0" inside the jail AND allow for a dynamic IP on that interface.

Also, this host is not a firewall, it's a host behind a firewall, so there is no "external" address - it's just a server on my LAN and the VPN instance is running not on the firewall, but on this server (OpenVPN only needs a single UDP or TCP port to work, unlike IPSEC, so running it inside the LAN is easy/uncomplicated).

This is the current jail.conf:


```
[spork@media ~]$ cat !$
cat /etc/jail.conf
# shared settings
exec.start += "sleep  2 ";
allow.raw_sockets = 1;
exec.clean;
exec.system_user = "root";
exec.jail_user = "root";
exec.start += "/bin/sh /etc/rc";
exec.stop = "";
mount.devfs;
mount.fstab = "/etc/fstab.$name";
mount.fdescfs;
allow.mount;
allow.set_hostname = 1;

private {
    exec.fib = 1;
    host.hostname = "private.example.com";
    ip4.addr += "10.9.0.8"; # TUN0 IP/VPN
    ip4.addr += "10.3.2.9"; # LOCAL LAN
    path = "/jails/private.example.com";
    mount +=  "procfs /jails/private.example.com/proc procfs rw 0 0";
    exec.consolelog = "/var/log/jail_priv_console.log";
}
```

The jail is on it's own FIB so it can have a default route out the tun0 device instead of the LAN.

OpenVPN is started in the jail, also on it's own FIB:

`setfib -F 1 /usr/local/sbin/openvpn-client /usr/local/etc/openvpn/mullard.conf`

This all works...  Until I need to reconnect the VPN.  At that point I have to put a new IP in jail.conf and restart the jail.  I need something that doesn't require manual intervention.  I do have the jail protected at the firewall - any traffic from "10.3.2.9" can't reach the internet, so the jail does lose connectivity when the VPN goes down (this is a requirement, obviously - I don't want to ever send traffic out of this jail other than via the VPN).


----------



## ShelLuser (Jul 17, 2018)

Chris_H solution is pretty on the mark. I think you're overestimating what you can do with a Jail.

To put this very simple: a jail cannot set up any networking configurations on its own. If you look at that same jail(8) manualpage you'll notice that the use of the ip4 setting is tied into ip4.addr, I quote: "_A list of IPv4 addresses assigned to the jail._". Because that's the only way a jail works: stuff gets assigned to it.

You won't be able to "just" mount media from inside a jail unless it has been granted on the host. You won't be able to "just" use networking inside a jail (think about ICMP) unless you set this up on the host, and so on.

And dynamic IP addresses inside a jail also won't work: it'll be the host that sets all of that up.

As such it's actually a good idea to set up your jail on a local loopback device, then set up your VPN on the host after which you can use a firewall such as pf to forward incoming data onto the jail.


----------



## spork (Jul 17, 2018)

I think it is possible, it's in the manpage, and Mark Feld (see link in first post) is doing this, just with a prior version where jail.conf had a bit more flexibility.  I'll give it a shot with the old rc.conf jail code I guess.


----------



## ShelLuser (Jul 17, 2018)

spork said:


> I think it is possible, it's in the manpage


Nothing in the manualpage states that jails can act as a DHCP client. Why do you think ip4.addr and ip6.addr exist?

As to that blog you linked to: please note the _static_ IPv4 address which got assigned to the jail through use of ip4.addr. And just because someone on a random blog states that you could use a certain option doesn't automatically make that true.

Instead, if you do some research on people who have been here before you'll notice the exact same suggestion which Chris_H mentioned earlier. See for example this post on the mailinglist or this forum thread.

A jail gets IP addresses assigned to it and has no control over that process, because that's restricted to the host. This is simply the (somewhat restricted) way in which jails work.


----------



## spork (Jul 17, 2018)

The jail manpage was quoted above. Note the "inherit" option.  

There's no DHCP involved here, this is a VPN connection using the "tun0" interface.  The host doesn't even route any traffic over that interface.  This is an entirely different scenario from either of the posts your quoting.

They are getting routable IPs via DHCP on the host and then NAT'ing that to the jail.  That is not what I'm doing.

If I were to try to narrow this down to the simplest question, it would be "how do I get the ip4 'inherit' flag set via jail.conf?" (as noted in the jail manpage quoted above)


----------



## Chris_H (Jul 17, 2018)

Hey spork ! 
You're almost there. _Really_. 
If I were you, I take a good long look at pf.conf(5). You *can* do it, and I'm cheering for you.
If I had a clearer picture of what you're _really_ trying to do. I'd probably be of more assistance. But I'd need better details. 
Really, pf(4) is your friend here, and _will_ get you to your desired destination. 

--Chris
EDIT
pf is just as much *routing* as it is "firewall". Don't let the fact that it's often called, and used as "firewall" mislead you. After all, isn't filtering, just another name for routing?


----------



## spork (Jul 18, 2018)

D'oh!

"ip4.addr=inherit" is NOT the same as "ip4=inherit"

That works ("works" here meaning I can change the tun0 IP at will and it still works), and the jail is basically unrestricted as far as networking goes.  Sadly I can't, for example allow ONLY tun0 in the jail.

What I'm _really_ trying to do?   Have a jail that only has access to the internet via a VPN (not a corporate VPN, VPN as in Mullard, NordVPN, PIA, etc.).

The NAT option I think assumes that I am OK with the host having OpenVPN running in the same FIB, and I'm not.  The intersection of pf and FIBs is a bit scary, so I'm trying to avoid that.

I have a few paths to try:

Just use VIMAGE for the jail (why is VIMAGE still not in GENERIC for 11.2???).  This seems well-supported and there are a ton of HOWTOs on that since FreeNAS uses iocage/VIMAGE jails.  For example: https://forums.freenas.org/index.ph...-a-jail-so-it-only-connects-to-the-vpn.18669/

Use a normal jail, pretty much where I started with this post, but add some commands to the vpn up/down script to run "jail -m new_vpn_ip,local_lan_ip", which should allow the jail to keep running, but adjust for any VPN IP changes.  This seems easier...


----------



## Chris_H (Jul 18, 2018)

Congrats, spork !


> Use a normal jail, pretty much where I started with this post, but add some commands to the vpn up/down script to run "jail -m new_vpn_ip,local_lan_ip", which should allow the jail to keep running, but adjust for any VPN IP changes.  This seems easier...


If it were me. That's pretty close to the direction *I* would travel.

Careful tho. I think you may be trying to over complicate things a little.

--Chris


----------



## spork (Jul 21, 2018)

Well, I never played with VIMAGE before, and I figure it's going to either show up in 11.3 or 12.1 will be a safe release when it arrives.

So VIMAGE makes this really easy, as you have a little virtualized network stack in the jail.  Just add an "unhide" rule for "tun*" in the jail's devfs ruleset and you can run OpenVPN inside the jail.  So far, it's been working great.  To protect from possible VPN outages/failures, I've simply limited access from this jail's IP at my pfsense box so that it can only reach the VPN server IPs.  VPN goes down, jail is not going to "leak"...

Biggest pain with all of this is that the 3rd party tools that manage jails (iocage, iocage-new, cbsd) have really outpaced the handbook and other documentation - I found the easiest way to figure out VIMAGE (and the resoure limits that I'm not using, but was curious about) was to poke at the iocage source/scripts.


----------



## PMc (Jul 21, 2018)

spork said:


> Basically, I need to get "tun0" inside the jail AND allow for a dynamic IP on that interface.



Not necessarily. I am using the same configuration as You describe (host is connected to normal network, while jail talks via VPN to a special outside world and is reachable from there), only that my jail has a _costant/static_ IP for that purpose.

My openvpn runs _outside_ of the jail (started from jail.conf with `exec.poststart`), the tunX is configured with private IPs 10.1.1.26 <-> 10.1.1.20 (these are never routed), and the actually used static IP is an alias on lo0:

```
lo0       - 127.0.0.0/8   127.0.0.1            35722     -     - 10917909     -     -
lo0       - 198.51.100.23/32   198.51.100.23          50913     -     -    19210     -     -
tun1   1411 <Link#11>     tun1                 29656     0     0    45021     0     0
tun1      - 10.1.1.26/32 10.1.1.26               0     -     -    10067     -     -
```
Then the jail has `ip4.addr = "198.51.100.23";` so that incoming traffic will get to the jail, and the outgoing routing is done with `ipfw`, like this:
`ipfw add 15501 fwd 10.1.1.20 tcp from 198.51.100.23 smtp,ssh,ftp,http,https to not 192.168.0.0/16`

The remaining difficulty is how to make such work for a dynamic IP, i.e. how to tell the jail to change it's IP.


----------



## spork (Aug 1, 2018)

PMc said:


> The remaining difficulty is how to make such work for a dynamic IP, i.e. how to tell the jail to change it's IP.



Yeah, that's why I pretty much went with another option - I need to use the dynamic IP my provider supplies and I really hate enabling ipfw/ipf/pf on an internal host unless there's good reason to.  VIMAGE has been working great. A billing issue with the vpn provider also confirmed to me that the "block all but vpn traffic" rules are working on my pfsense box in front of all this mess.


----------

