# Routing problem with WLAN



## free-and-bsd (Jan 13, 2016)

Hello everyone,

I'm having problems with routing for WLAN. The idea is to route WLAN Internet traffic to the OpenVPN tun0 interface on my laptop, which acts as wifi Access Point.

I have a laptop acting as AP. It has a VPN connection through tun0, which is made a default route upon connection. The connection is manual, no mention of it in /etc/rc.conf.
Upon connection the routing table of the laptop looks like this:

```
Internet:
Destination  Gateway  Flags  Netif Expire
default  172.16.55.1  UGS  tun0
${hidden}  192.168.24.1  UGS  em0
127.0.0.1  link#2  UH  lo0
172.16.55.0/24  172.16.55.2  UGS  tun0
172.16.55.1  link#4  UH  tun0
172.16.55.2  link#4  UHS  lo0
192.168.24.0/24  link#1  U  em0
192.168.24.100  link#1  UHS  lo0
192.168.28.0/27  link#3  U  wlan0
192.168.28.1  link#3  UHS  lo0
```
There one can see
"${hidden}  192.168.24.1" -- that's connection to VPN server with IP ${hidden} through my router's gateway 192.168.24.1;
then 192.168.24.0/24 -- that's from laptop to gateway router, wired;
the 172.16.55.0/24 network, that's VPN tunnel net;
then 192.168.28.0/27 -- that's WLAN.

My wlan0 is configured through isc-dhcpd and clients are given as default route the wlan0's IP = 192.168.28.1. But somehow the Internet requests coming from WLAN are not sent to the laptop's default route, at the time it's 172.16.55.1 from the OpenVPN net, as shown in the route table above.

At the same time this address can be pinged from the Android tablet. Which indicates that routing works OK. There is NAT translation from VPN net to WLAN and back. But Internet hosts can't be pinged, which tells me that Internet requests from WLAN are _not_ forwarded to system's default gateway.

QUESTION:
What might be the matter and why isn't computer's default route used for Internet requests from WLAN? I don't need any specific configuration for that, do I? Except ip forwarding, which _is_ enabled  via gateway_enable="YES" in /etc/rc.conf.


----------



## Juha Nurmela (Jan 13, 2016)

Does the _gateway_enable_ suffice?


```
# grep forw /etc/sysctl.conf
net.inet.ip.forwarding=1
```

Juha

Edit: It suffices, sorry about that.


----------



## free-and-bsd (Jan 14, 2016)

And anyways, I _do_ have a good proof that forwarding IS working: I've changed the configuration a bit replacing wlan0 and WLAN with second wired interface re1 and second LAN accordingly.

So, routing and forwarding works perfectly well as long as normal routing is involved: Internet connection forwarded from re0 to re1. But as soon as I connect VPN and tun0 is created, which automatically replaces default root for that through the tunnel, there is no routing for re1 and its LAN. That is, VPN network 172.16.55.0/24 can be pinged from hosts connected to re1, but Internet connection is _not_ forwarded.

I think I will ask this same question on OpenVPN forums where they have helped me on a couple of occasions, and this issue may well be related to OpenVPN.
For example, in ssh there is that option GatewayPorts which allows/forbids the usage of the tunnel by any hosts other than localhost. Could it be OpenVPN had the same kind of feature? We'll see...

Or perhaps, setfib could somehow be used to resolve this problem? But my idea of its usage is pretty hazy...


----------



## kpa (Jan 14, 2016)

You definitely need NAT on the VPN tunnel because the other end of the tunnel is unlikely to know that your local WLAN network uses 192.168.28.0/27 addresses (strange choise for netmask, why not just /24 ?). With PF it would be simply:


```
nat on tun0 inet from ! tun0 from any to any -> tun0
```

That can be automated with up/down OpenVPN scripts and use of PF anchors.

Your assesment of routing not working is wrong, it is but only in the outgoing direction on the VPN tunnel.


----------



## PacketMan (Jan 14, 2016)

Check to verify you have the correct routes backs.  I see so many network folks think to where they need stuff to go, but often forget the reply traffic needs to come back.

And me thinks this discussion should be moved to the networking section.


----------



## free-and-bsd (Jan 14, 2016)

Yes, thanks a lot for moving it over to the right section. How could I overlook the existence of "Networking" section?? I've really been in a somewhat disturbed mood over this pesky problem, sorry for that...



kpa said:


> You definitely need NAT on the VPN tunnel because the other end of the tunnel is unlikely to know that your local WLAN network uses 192.168.28.0/27 addresses (strange choise for netmask, why not just /24 ?). With PF it would be simply:
> 
> 
> ```
> ...


Sure and I think the second "from" is one too many in your rule above, don't you think so ? I can imagine what pfctl will reply to that rule of yours...

And then this was in my post:


free-and-bsd said:


> ...That is, VPN network 172.16.55.0/24 *can* be pinged from hosts connected to re1, but Internet connection is _not_ forwarded.


 Doesn't this indicate that NAT translation between the two networks is all right?

Anyways, no more guessing, here is my /etc/pf.conf:

```
out_if = "re1"
vpn_if = "tun0"
wir_if = "re0"

set block-policy return
set skip on lo0

nat on $out_if from 192.168.24.0/24  to any -> ($out_if)
nat on $wir_if from 192.168.26.0/27 to any -> ($wir_if)
nat on $out_if from 172.16.55.0/24 to any -> ($out_if)
nat on $vpn_if from any to 172.16.55.0/24 -> ($vpn_if)
nat on $out_if from any to 192.168.26.0/27 -> ($out_if)
#rdr pass on $out_if proto { tcp,udp } from 192.168.26.0/27 to 0.0.0.0 -> 172.16.55.2
anchor openvpn

pass in quick on $wir_if from any to any
pass out quick on $wir_if from any to any
pass in quick on $out_if from any to any
pass out quick on $out_if from any to any

block in quick all
block out quick all
```
 In here re0 is connected to router from which it gets Internet initially. Then re1 is LAN to which default gateway is forwarded.

For anchor openvpn I have this in a separate file, to be loaded after tun0 brought up:

```
pass out quick on tun0 from any to any keep state
pass in quick on tun0 from any to any keep state
```
This is because until tun0 is up PF will not accept any filtering rules related to it, only NAT, so they're there.
So I start openvpn like this:

```
sudo openvpn [options] && sudo pfctl -a openvpn -f /etc/pf.conf.openvpn
```

So, my NAT translation rules are somewhat explicit, because of my experience with firewalls that "from any to any" may not suffice in some complicated cases. Among other things one can see that I translate explicitly in both ways between 172.16.55.0/24 and 192.168.28.0/27 -- just to make sure this happens. In fact, I only want to forward tun0 to 192.168.28.0/27, that's why.

What _else_ is to be translated and how -- this is beyond me. I'm only sure that no routes need be _pushed_ to the LAN clients. Know that from working LAN clients with "straight" configuration (wired based), they have only this route: LAN + gw on the same LAN. All routing then is expected to take place inside the _router_ host.


----------



## kpa (Jan 14, 2016)

Yeah sorry the rule should be without the second from:


```
nat on tun0 inet from ! tun0  to any -> tun0
```

Basically you have two options for making the traffic reach the other end of the tunnel and the return traffic to traverse back properly.

First one is that you tell the system other end of the tunnel that you have a network 192.168.28.0/27 at your end of the tunnel that can be reached via the tunnel. In the OpenVPN configuration at the other end this would be:


```
route 192.168.28.0/27
```

The second one is that you "hide" the network 192.168.28.0/27 using NAT as I first suggested. This would make all traffic coming from 192.168.28.0/27 going over the tunnel to appear as it was coming from the local tunnel endpoint address and the remote end wouldn't have to know anything about the local network 192.168.28.0/27

Ping is not a reliable test tool for sorting out routing problems, start using tcpdump(1).


----------



## free-and-bsd (Jan 15, 2016)

Ok, finally I've found the ruleset that works.

```
out_if = "re1"
vpn_if = "tun0"
wir_if = "re0"

set block-policy return
set skip on lo0

nat on $out_if from ! $out_if  to any -> ($out_if)
nat on $wir_if from ! $wir_if to any -> ($wir_if)
nat on $vpn_if from ! $vpn_if to any -> ($vpn_if)

anchor openvpn

pass in quick on $wir_if from any to any
pass out quick on $wir_if from any to any
pass in quick on $out_if from any to any
pass out quick on $out_if from any to any

block in quick all
block out quick all
```
Thank you kpa for your idea to use `from ! $my_iface to any` syntax. This obviously takes care of everything, while the more explicit `from $my_network/netmask to any` evidently leaves some important stuff out.

So now with this rather simplistic ruleset everything works as expected. Logical, too.
The only drawback here is that the tun0 related parts are only accepted when tun0 is up. So I load this config when tun0 is up.


----------



## kpa (Jan 15, 2016)

You can automate that with up/down OpenVPN scripts. Put this in your OpenVPN client configuration:


```
script-security 2

up /usr/local/etc/openvpn/up.sh
down /usr/local/etc/openvpn/down.sh
```

The up.sh script:


```
#!/bin/sh

ANCHOR=openvpn

/sbin/pfctl -a "${ANCHOR}" -F rules
/sbin/pfctl -a "${ANCHOR}" -F nat
/sbin/pfctl -a "${ANCHOR}" -f - <<EOT
nat on "${dev}" inet from ! "${dev}" to any -> ("${dev}")
pass quick on "${dev}" all
EOT
```

The down.sh script:


```
#!/bin/sh

ANCHOR=openvpn

/sbin/pfctl -a "${ANCHOR}" -F rules
/sbin/pfctl -a "${ANCHOR}" -F nat
```

OpenVPN will pass the interface in the dev environment variable to the script when it's run.

Then you need the anchors in your PF rules:


```
...
# Put this where NAT rules normally go
nat-anchor "openvpn"
...
# Filter rules, place appropriately
anchor "openvpn"
...
```

You can fine tune access on the tunnel by modifying the `pass quick on "${dev}" all` rule in the up.sh, now it passes everything without restrictions.


----------



## free-and-bsd (Jan 15, 2016)

Thank you again kpa , I didn't know about nat-anchor but have ovserved that anchor doesn't load nat rules put into it.

And this option for added scripts into OpenVPN client config, that's very useful. My problem is, I never have enough time to study these things in-depth unless some task requires it. And my task is usually limited to troubleshooting problems.

So I used to start openvpn like

```
sudo service openvpn onestart && sudo pfctl -a openvpn -f /etc/pf.conf.openvpn
```

Thank you very much for useful information.


----------



## free-and-bsd (Jan 15, 2016)

kpa said:


> You can automate that with up/down OpenVPN scripts. Put this in your OpenVPN client configuration:
> 
> 
> ```
> ...


For some reason the down script only works when I start VPN from command line. When started via `service openvpn etc` it only uses up.sh, but evidently doesn't reach the
down.sh.
Perhaps, /usr/local/etc/rc.d/openvpn needs debugging here...
.


----------



## free-and-bsd (Jan 15, 2016)

Well, it seems to be no bug, but the result of the process being set to GID nogroup, UID nobody. In this character it is not allowed to alter PF rules or do any such thing:

```
Fri Jan 15 19:14:33 2016 /sbin/route add -net 192.168.0.0 10.0.0.1 255.255.255.224
add net 192.168.0.0: gateway 10.0.0.1
Fri Jan 15 19:14:33 2016 GID set to nogroup
Fri Jan 15 19:14:33 2016 UID set to nobody
Fri Jan 15 19:14:33 2016 Initialization Sequence Completed
Fri Jan 15 19:14:46 2016 event_wait : Interrupted system call (code=4)
Fri Jan 15 19:14:46 2016 /sbin/route delete -net 192.168.0.0 10.0.0.1 255.255.255.224
route: must be root to alter routing table
Fri Jan 15 19:14:46 2016 ERROR: FreeBSD route delete command failed: external program exited with error status: 77
Fri Jan 15 19:14:46 2016 Closing TUN/TAP interface
Fri Jan 15 19:14:46 2016 /sbin/ifconfig tun0 destroy
ifconfig: SIOCIFDESTROY: Operation not permitted
Fri Jan 15 19:14:46 2016 FreeBSD 'destroy tun interface' failed (non-critical): external program exited with error status: 1
...
pfctl: /dev/pf: Permission denied
pfctl: /dev/pf: Permission denied
Fri Jan 15 19:14:46 2016 WARNING: Failed running command (--up/--down): external program exited with error status: 1
Fri Jan 15 19:14:46 2016 Exiting due to fatal error
```


----------



## free-and-bsd (Jan 15, 2016)

free-and-bsd said:


> Well, it seems to be no bug, but the result of the process being set to GID nogroup, UID nobody. In this character it is not allowed to alter PF rules or do any such thing


.
This is defined in my config as :

```
user nobody
group nogroup
```
So, all questions settled now. Can set status to [SOLVED].
Thanks to everyone


----------



## kpa (Jan 15, 2016)

You can possibly leave out the down.sh script and then run under nobody/nogroup because the up.sh will flush out the old rules at start up before adding new. I'm just not sure how PF in FreeBSD responds to dangling rules that refer to non-existing interaces.


----------



## free-and-bsd (Jan 15, 2016)

kpa said:


> You can possibly leave out the down.sh script and then run under nobody/nogroup because the up.sh will flush out the old rules at start up before adding new. I'm just not sure how PF in FreeBSD responds to dangling rules that refer to non-existing interaces.


Not only the rules remain in place, but also device tun0 because unprivileged daemon fails to destroy it upon exit. So the rules actually refer to an existing, though non-functional, interface in this case.
Actually, the up.sh is run before dropping privileges, that's why no problems here.
But I've never observed any complications from the dangling rules that refer to non-existent interfaces. As I see it now, this dropping of privileges is expected to work all right with the openvpn which starts/stops upon system startup/shutdown.
And for custom on-demand starting from command line one can execute the needed commands from command line. Then there's also chroot option.


----------

