Solved vnet jail unreachable from both ends

Hello folks,

this is my first attempt configuring a jail using VNET. Previously I have always used to deploy jails using alias of the external interface.

So, I took this /etc/jail.conf from a user on reddit, and based on my understanding it does(should do) the following:

1. A bridge is created between the $uplink(ext inf) and epairXa interfaces
2. epairXb interfaces are added to the jails and named jail0 inside each jail
3. The jail on (jail0)epairXb should be reachable from the host through bridge0 as both epairXa and uplink interface have been added to i
t

Code:
# Global settings applied to all jails.

exec.system_user  = "root";
exec.jail_user    = "root";
mount.devfs;
allow.raw_sockets;
devfs_ruleset     = "5";

# Networking and the exec cycle
$uplinkdev        = "vtnet0";
vnet;
vnet.interface    = "jail0";  # default vnet interface
exec.prestart     = "ifconfig bridge0 > /dev/null 2> /dev/null || ( ifconfig bridge0 create up && ifconfig bridge0 addm $uplinkdev )";
exec.prestart    += "ifconfig $epair create up                 || echo 'Skipped creating epair (exists?)'";
exec.prestart    += "ifconfig bridge0 addm ${epair}a           || echo 'Skipped adding bridge member (already member?)'";
exec.created      = "ifconfig ${epair}b name jail0             || echo 'Skipped renaming ifdev to jail0 (looks bad...)'";
exec.clean;
exec.start        = "/bin/sh /etc/rc";
exec.stop         = "/bin/sh /etc/rc.shutdown";
exec.poststop     = "ifconfig bridge0 deletem ${epair}a";
exec.poststop    += "ifconfig ${epair}a destroy";

# Per-jail settings
www {
    path          = "/jails/www0/12.1-RELEASE/root";
    host.hostname = "www";
    $epair        = "epair0";  # must be unique in every jail
    exec.consolelog = "/jails/www0/console.log";
}

Output of jls and ifconfig from the host
Code:
[admin@lockdown ~]$ jls
   JID  IP Address      Hostname                      Path
     2                  www                           /jails/www0/12.1-RELEASE/root

[admin@lockdown ~]$ ifconfig
vtnet0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> metric 0 mtu 1500
    options=2c00b9<RXCSUM,VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,VLAN_HWTSO,LINKSTATE,RXCSUM_IPV6>
    ether 5e:b6:5e:bd:84:58
    inet 10.16.0.101 netmask 0xffffff00 broadcast 10.16.0.255
    media: Ethernet 10Gbase-T <full-duplex>
    status: active
    nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
    options=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
    inet6 ::1 prefixlen 128
    inet6 fe80::1%lo0 prefixlen 64 scopeid 0x2
    inet 127.0.0.1 netmask 0xff000000
    groups: lo
    nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
bridge0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
    ether 02:35:3b:a8:4b:00
    id 00:00:00:00:00:00 priority 32768 hellotime 2 fwddelay 15
    maxage 20 holdcnt 6 proto rstp maxaddr 2000 timeout 1200
    root id 00:00:00:00:00:00 priority 32768 ifcost 0 port 0
    member: epair0a flags=143<LEARNING,DISCOVER,AUTOEDGE,AUTOPTP>
            ifmaxaddr 0 port 4 priority 128 path cost 2000
    member: vtnet0 flags=143<LEARNING,DISCOVER,AUTOEDGE,AUTOPTP>
            ifmaxaddr 0 port 1 priority 128 path cost 2000
    groups: bridge
    nd6 options=1<PERFORMNUD>
epair0a: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> metric 0 mtu 1500
    options=8<VLAN_MTU>
    ether 02:99:c4:4f:68:0a
    inet6 fe80::99:c4ff:fe4f:680a%epair0a prefixlen 64 scopeid 0x4
    groups: epair
    media: Ethernet 10Gbase-T (10Gbase-T <full-duplex>)
    status: active
    nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
[admin@lockdown ~]$

/etc/rc.conf in www jail
Code:
clear_tmp_enable="YES"
sendmail_enable="NONE"
keymap="uk.kbd"
ifconfig_jail0="inet 192.168.60.254 netmask 255.255.255.0

ifconfig from the jail
Code:
# ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
    options=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
    inet6 ::1 prefixlen 128
    inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
    inet 127.0.0.1 netmask 0xff000000
    groups: lo
    nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
jail0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
    options=8<VLAN_MTU>
    ether 02:99:c4:4f:68:0b
    inet 192.168.60.254 netmask 0xffffff00 broadcast 192.168.60.255
    groups: epair
    media: Ethernet 10Gbase-T (10Gbase-T <full-duplex>)
    status: active
    nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>

Pinging the host from the www jail will return a Network is unreachable error. Interestingly, when pining the www jail from the host, the ping is stuck. A traceroute shows the host goes all the way down to my router to find 192.168.60.0/24 and than dies
Code:
[admin@lockdown ~]$ traceroute 192.168.60.254
traceroute to 192.168.60.254 (192.168.60.254), 64 hops max, 40 byte packets
1  10.16.0.1 (10.16.0.1)  0.569 ms  1.208 ms  0.641 ms
2  OpenWrt.lan (172.12.0.1)  1.655 ms  1.596 ms  0.950 ms
3  * * *
4  * * *
[admin@lockdown ~]$

Even adding a static route inside the www jail won't help resolving the host. Where am I doing wrong? I am really not good at networking.

Thanks
 
Last edited:
Hi,
VNET jail is really cool and I love it so much.

As you've created a bridge between vtnet0 and epair, the jail and the host are connected to the same broadcast domain (just like they are connected to the same switch).

So usually they have to have IP addresses in the same subnet.
In your case, changing the jail's IP address to the one in 10.16.0.1 - 10.16.0.254 range would let the jail and the host (or other hosts on the same subnet) communicate each other.

If the jail wants to go beyond your router, it also needs a default route and (maybe) name server information, which should be the same as the host.
For the latter, just copying the host's /etc/resolv.conf to the jail will suffice.
The jail's rc.conf might have something like:
Code:
# assume 10.16.0.201 is not used by others and 10.16.0.1 is your router.
ifconfig_jail0="inet 10.16.0.201 netmask 255.255.255.0
defaultrouter="10.16.0.1"

Those configuration might be also done in the host's /etc/jail.conf using exec.start and exec.prestart.
 
Hi,
VNET jail is really cool and I love it so much.

As you've created a bridge between vtnet0 and epair, the jail and the host are connected to the same broadcast domain (just like they are connected to the same switch).

So usually they have to have IP addresses in the same subnet.
In your case, changing the jail's IP address to the one in 10.16.0.1 - 10.16.0.254 range would let the jail and the host (or other hosts on the same subnet) communicate each other.

If the jail wants to go beyond your router, it also needs a default route and (maybe) name server information, which should be the same as the host.
For the latter, just copying the host's /etc/resolv.conf to the jail will suffice.
The jail's rc.conf might have something like:
Code:
# assume 10.16.0.201 is not used by others and 10.16.0.1 is your router.
ifconfig_jail0="inet 10.16.0.201 netmask 255.255.255.0
defaultrouter="10.16.0.1"

Those configuration might be also done in the host's /etc/jail.conf using exec.start and exec.prestart.

I cannot believe I am so dumb 😔. Btw, if I want jail0 to be on a different subnet that the host is, do I have to ditch bridge and do routing between epair0a and epair0b as if these were two normal interfaces?

Thanks
 
Don't worry. VNET is so powerful but surely there's something complex about it 😋.

To place the jail in a different subnet from the host's uplink (vtnet0), yes, get rid of the bridge and assign IP addresses in the subnet to both ends of the epair.

For example, assign 192.168.60.101/24 to the host (epair0a) and 192.168.60.254/24 to the jail (jail0 = epair0b) as follows.
Code:
                                  +-- Host ------------------------+
                  10.16.0.0/24    |        192.168.60.0/24         |
                                  |                                |
               .1            .101 |      .101           .254       |
///--o[Router]o--------///-------o[Host]o------epair0------o[Jail] |
                            vtnet0|     epair0a        jail0       |
                                  |                  (epair0b)     |
                                  +--------------------------------+

In this configuration, the host has two IP interfaces and has to forward packets between them as another router.
This can be achived by running sysctl net.inet.ip.forwarding=1 on the host.
Adding gateway_enable="YES" to /etc/rc.conf on the host ensures it after reboots.

Then configure the jail's default gateway to the host's epair0a address, 192.168.60.101.

At this point, the jail can communicate with the host and it can also reach hosts on the 10.16.0.0/24 subnet (attached to the host's vtnet0),
but those hosts cannot reach back to the jail because they do not have a route to the jail's subnet (192.168.60.0/24).

The solution may vary depending on your needs but the easiest one would be performing NAT on the host.
If you use PF, something like below in /etc/pf.conf can translate the source address of packets from the jail to the host's external address (on vtnet0) and vice versa for the returned packets.
Code:
nat on vtnet0 inet from 192.168.60.0/24 to any -> (vtnet0)

Now the jail can communicate with the outside world (= it can send packets to outside hosts and can receive their replies if they are not blocked).

As I guess from the jail's name (www), if you also want the outside hosts to be able to access services on the jail, you can setup port fowarding rules on the host.

I'm by no means an expert, but I hope this helps😊.
 
Ehm right.. I am having trouble reaching the jail subnet from my router, and apparently I cannot add a static route on my router since the FreeBSD host doesn't seem to have the jail subnet route, or so I think. Here's the configuration recap.

FreeBSD host: 10.16.0.101; vtnet0
Jail subnet: 192.168.69.0/24; epair0a
Jail www: 192.168.69.254; epair0b (jail0)
OpenWrt router: 172.12.0.1; can reach 10.16.0.0/24 and viceversa

How the situation looks in the FreeBSD host:
Code:
[admin@lockdown ~]$ traceroute -v 192.168.69.254
traceroute to 192.168.69.254 (192.168.69.254), 64 hops max, 40 byte packets
 1  192.168.69.254 (192.168.69.254) 48 bytes to 192.168.69.1  0.194 ms  0.138 ms  0.095 ms
[admin@lockdown ~]$ 

[admin@lockdown ~]$ netstat -r
Routing tables

Internet:
Destination        Gateway            Flags     Netif Expire
default            10.16.0.1          UGS      vtnet0
10.16.0.0/24       link#1             U        vtnet0
10.16.0.101        link#1             UHS         lo0
localhost          link#2             UH          lo0
192.168.69.0/24    link#4             U       epair0a
192.168.69.1       link#4             UHS         lo0

Internet6:
Destination        Gateway            Flags     Netif Expire
::/96              localhost          UGRS        lo0
localhost          link#2             UH          lo0
::ffff:0.0.0.0/96  localhost          UGRS        lo0
fe80::/10          localhost          UGRS        lo0
fe80::%lo0/64      link#2             U           lo0
fe80::1%lo0        link#2             UHS         lo0
fe80::%epair0a/64  link#4             U       epair0a
fe80::99:c4ff:fe4f link#4             UHS         lo0
ff02::/16          localhost          UGRS        lo0
[admin@lockdown ~]$

pf configuration on the host:
Code:
ext_if="vtnet0"

IP_JAIL_www="192.168.69.254"
NET_JAIL="192.168.69.0/24"

scrub in all

# nat all jail traffic
nat on $ext_if inet from $NET_JAIL to any -> ($ext_if)

# Allow ICMP ping
pass inet proto icmp from any to any

# allowing all traffic IN/OUT (unsafe)
pass out
pass in

As you can see from the traceroute, 192.168.69.254 is resolved directly through the epair0a, and from netstat I cannot see any route between 10.16.0.0/24 and 192.168.69.0/24. If I add a static route on the host between 192.168.69.0/24 and 10.16.0.101 a mayhem happens and the jail subnet becomes unreachable.

If however I try adding a static route on the OpenWrt router, 192.168.69.0/24 doesn't seem to be available through 10.16.0.101.
Code:
root@OpenWrt:~# ip route add 192.168.60.0/24 via 10.16.0.101 dev br-lan
ip: RTNETLINK answers: Network unreachable
root@OpenWrt:~#

Would I need to do some kind of subnet forwarding through pf or what exactly? I do apologise for the noob questions but I am very bad at networking, especially in freebsd :)
 
No problem!
I'm also always learning by trial and error and I think it's a good way to truly understand something.

I can see at least two things to check.

(1) Is the jail subnet address 192.168.60.0/24 or 192.168.69.0/24?
It looks like you tried to add a route to the former network but the host and the jail are setup with the latter.
Is 192.168.60.0/24 in the following command line just a typo on the forum?

Code:
root@OpenWrt:~# ip route add 192.168.60.0/24 via 10.16.0.101 dev br-lan

(2) Do you want your OpenWRT router to directly communicate with the jail subnet?
If so, you don't need NAT on the host.
With your current NAT rule, even if the router can have a route to the jail subnet and can send a packet to the jail, a return packet's source address will be translated to the host's address and the router cannot recognize it as a reply from the jail.

Code:
[Router]                                [Host]                                 [Jail]
   10.16.0.1 ------> 192.168.69.254 (Just Forward) 10.16.0.1 ------> 192.168.69.254
   10.16.0.1 <------ 10.16.0.101     (NAT Source)  10.16.0.1 <------ 192.168.69.254
 
No problem!
I'm also always learning by trial and error and I think it's a good way to truly understand something.

I can see at least two things to check.

(1) Is the jail subnet address 192.168.60.0/24 or 192.168.69.0/24?
It looks like you tried to add a route to the former network but the host and the jail are setup with the latter.
Is 192.168.60.0/24 in the following command line just a typo on the forum?



(2) Do you want your OpenWRT router to directly communicate with the jail subnet?
If so, you don't need NAT on the host.
With your current NAT rule, even if the router can have a route to the jail subnet and can send a packet to the jail, a return packet's source address will be translated to the host's address and the router cannot recognize it as a reply from the jail.

Code:
[Router]                                [Host]                                 [Jail]
   10.16.0.1 ------> 192.168.69.254 (Just Forward) 10.16.0.1 ------> 192.168.69.254
   10.16.0.1 <------ 10.16.0.101     (NAT Source)  10.16.0.1 <------ 192.168.69.254


Hey, sorry for the confusion. Yes I changed the jail's subnet to 192.168.69.0/24. The static route output from the router effectively shows me trying to add the former subnet, however that was a wrong paste as I was meant to paste the output of me adding the new subnet's route instead. Anyways, I am still stuck with the same issue:

Code:
root@OpenWrt:~# ip route add 192.168.69.0/24 via 10.16.0.101 dev br-lan
ip: RTNETLINK answers: Network unreachable
root@OpenWrt:~#

from one of the client in the LAN
Code:
marco@miner1:~$ ping  -c1 10.16.0.101
PING 10.16.0.101 (10.16.0.101) 56(84) bytes of data.
64 bytes from 10.16.0.101: icmp_seq=1 ttl=63 time=3.32 ms

--- 10.16.0.101 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 3.321/3.321/3.321/0.000 ms
marco@miner1:~$ 

marco@miner1:~$ sudo ip route add 192.168.69.0/24 via 10.16.0.101 dev wlo1
Error: Nexthop has invalid gateway.
marco@miner1:~$

So yeah, assuming I want to keep the jail's subnet to 192.168.69.0/24 and I do no want to use the bridge configuration in the FreeBSD host, what options do I have to reach 192.168.69.0/24 from my LAN?

In all honesty I have multiple linux VMs, each with their own virtual nics and different subnets, and all of them reachable from LAN through static routes on the OpenWRT router.

Thanks :)
 
Hi!
It seems I had misunderstood your network topology.
I had been thinking that 10.16.0.1 (the host's default gateway) was OpenWrt's LAN I/F address but just realized it's not. You mentioned that several times but I completely overlooked it...

FreeBSD host: 10.16.0.101; vtnet0
Jail subnet: 192.168.69.0/24; epair0a
Jail www: 192.168.69.254; epair0b (jail0)
OpenWrt router: 172.12.0.1; can reach 10.16.0.0/24 and viceversa

So, does your network look like this?

Code:
                                              +-- Host -----------------------+
            172.12.0.0/24       10.16.0.0/24  |        192.168.69.0/24        |
                                              |                               |
             .1      .X        .1        .101 |     .1             .254       |
---o[OpenWrt]o---///--o[Router]o-----///----o[Host]o------epair0------o[Jail] |
                 LAN                    vtnet0|     epair0a        jail0      |
                                              |                  (epair0b)    |
                                              +-------------------------------+

If so, the following route sould have a gateway via 172.12.0.X. I don't know what number "X" is but it must be the same as the existing static route to 10.16.0.0/24. via 10.16.0.101 was rejected because it's not on the same subnet as the OpenWrt.
(FYI: 172.12. addresses are not in the RFC1918 private range)
Code:
root@OpenWrt:~# ip route add 192.168.69.0/24 via 10.16.0.101 dev br-lan

The second question is about the Router in the above diagram. I guess it's a sort of virtual router.
It also has to have a route to the jail subnet (this time it's 192.168.69.0/24 via 10.16.0.101).

By the way, in this configuration, you do have three routers (OpenWrt, Router and Host) and you have to add routes to multiple routers.
One way to solve this is to do some dynamic routing, but if you just want your LAN hosts to access web or other services on the jail, how about adding NAT & port forwarding rules to the host again instead of adding a static route to the jail net on both the OpenWrt and the Router? In this case, the jails subnet is not visible outside of the host and they access the jail's services through the host's address (10.16.0.101).

pf.conf rules for this might be something like:
Code:
nat on $ext_if inet from $NET_JAIL to any -> ($ext_if)
rdr pass on $ext_if inet proto tcp to ($ext_if) port {80, 443} -> $IP_JAIL_www

Sorry for long and unorganized message, as always.
 
So okay I understood what the issue was. 10.16.0.0/24 is a VLAN that seats on the hypervisor 172.12.0.254. I realised 192.168.69.0/24 couldn't be reached from the hypervisor either.

So what I did was I set the static route inside the hypervisor first
Code:
root@node1:~# ip route add 192.168.69.0/24 via 10.16.0.101 dev vmbr1

than added the static route on the router to reach 10.16.0.0/24 through 172.12.0.254
Code:
root@OpenWrt:~# ip route add 192.168.69.0/24 via 172.12.0.254 dev br-lan

and now it all works. Thanks for helping me understanding this. :)
 
Back
Top