GL-MT300N-V2 as OpenVPN client need for Split Tunneling

Hello everyone,

I have a GL-MT300N-V2 running 3.012 firmware which I am using as OpenVPN client.
My objective is to connect my computer either via Ethernet to the LAN port or wireless via WiFi to the GL-MT300N-V2 and make it route Internet traffic locally using my WAN port (not through the OpenVPN’s TUN adapter) and only use the Tunnel created by OpenVPN to reach certain networks that my self setup OpenVPN Server is pushing to my GL-MT300N-V2 upon a successful OpenVPN client connection.

I noticed that even my OpenVPN Server is configured to not push a default route to my OpenVPN clients, the GL-MT300N-V2 is still creating the 0.0.0.0/1 and 128.0.0.0/1 in its Routing Table (overriding the 0.0.0.0/0 route to my WAN) to send all Internet traffic via the Tunnel. Also, when the OpenVPN client is up, the “zone_wan_dest” rule is removed under “zone_lan_forward” from the IPTables Firewall which drops traffic coming from LAN port that should be routed out the WAN port.

I’ll describe how I modified the internal scripts to make it work as per my objective. It works OK for me now. I would like to share that here in case someone find it useful.
I’d be great the GL.iNET Admin Panel had an HTML radio button in the OpenVPN Client configuration section with options such as “Remote networks only” or “Internet and Remote networks” for the user to have a choice.
Ubuntu’s Network Manager which administers the setup of OpenVPN client profiles has a checkbox called “Use this connection only for resources on its network” that controls this.

Next, how I made it work:

This is how the Routing Table looked in my GL-MT300N-V2 with the OpenVPN client connected to the Server. Notice the 0.0.0.0/1 and 128.0.0.0/1 entries.

root@GL-MT300N-V2:/etc/openvpn# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         0.0.0.0         128.0.0.0       U     0      0        0 tun0 <<<<
0.0.0.0         192.168.0.1     0.0.0.0         UG    10     0        0 eth0
10.8.0.0        0.0.0.0         255.255.255.0   U     0      0        0 tun0
x.x.x.x         192.168.0.1     255.255.255.255 UGH   0      0        0 eth0
128.0.0.0       0.0.0.0         128.0.0.0       U     0      0        0 tun0 <<<<
172.16.2.0      0.0.0.0         255.255.255.0   U     0      0        0 br-lan
192.168.0.0     0.0.0.0         255.255.255.0   U     10     0        0 eth0
192.168.1.0     10.8.0.1        255.255.255.0   UG    0      0        0 tun0

root@GL-MT300N-V2:/etc/openvpn# ip route
0.0.0.0/1 dev tun0 scope link <<<<
default via 192.168.0.1 dev eth0 proto static src 192.168.0.117 metric 10 
10.8.0.0/24 dev tun0 proto kernel scope link src 10.8.0.3 
x.x.x.x via 192.168.0.1 dev eth0 
128.0.0.0/1 dev tun0 scope link <<<< 
172.16.2.0/24 dev br-lan proto kernel scope link src 172.16.2.1 
192.168.0.0/24 dev eth0 proto static scope link metric 10 
192.168.1.0/24 via 10.8.0.1 dev tun0 

I found in the logs a hint that some script was doing additional stuff after the GL-MT300N-V2 connects to the OpenVPN Server…

root@GL-MT300N-V2:/etc/config# logread
. . .
Wed Jun 19 15:01:46 2019 user.notice firewall: Reloading firewall due to ifup of ovpn (tun0)
Wed Jun 19 15:01:49 2019 user.notice firewall: Reloading firewall due to ifup of ovpn (tun0)
Wed Jun 19 15:01:51 2019 user.notice root: check route success <<<

Looking into this forum, I learned about /etc/init.d/startvpn script which is called to start the OpenVPN Client connection to the Server.

root@GL-MT300N-V2:~# cat /etc/init.d/startvpn 

#!/bin/sh /etc/rc.common
. . .

start() {
. . .
	ovpn_firewall_start

	/usr/sbin/openvpn --config "$ovpn" --script-security 2 --dev $ifname --route-delay 2 --route-up /usr/bin/ovpn_check_route --remap-usr1 SIGHUP --writepid /var/run/ovpn_client.pid &

Inside function start( )

  • ovpn_firewall_start is another a function in this same file that ends up modifying the IPtables Firewall rules.
  • The –route-up parameter in the /usr/sbin/openvpn command calls a script /usr/bin/ovpn_check_route once the OpenVPN Client has connected to the Server but not before the Client has received the routes pushed by the Server.

This /usr/bin/ovpn_check_route is the one which actually yields “check route success” in the logs I showed previously and it also calls other scripts…

root@GL-MT300N-V2:~# cat /usr/bin/ovpn_check_route

#!/bin/sh
route=""
[ -d /sys/class/net/tun0 ] && {
	route=$(cat /proc/net/route|grep tun0)
	if [ -z "$route" ];then
		logger "check route failed tun0,restart ovpn"
		/etc/init.d/startvpn restart
	fi
	env -i ACTION="ifup" INTERFACE="ovpn" DEVICE="tun0" /sbin/hotplug-call iface
}
. . .
logger "check route success"

Ultimately, it is /etc/vpn.user script who inside ovpn_main( ) function, sets those 0.0.0.0/1 and 128.0.0.0/1 routes. I simply commented those lines for them to be ignored.

root@GL-MT300N-V2:~# cat /etc/vpn.user

#!/bin/sh
. . .

ovpn_main() {
. . .
	# Load default rules
	if [ "$INTERFACE" = "ovpn" ]; then
		# add default rules and force to main table
		[ -z "$(ip route list | grep -E "0.0.0.0/1 (.*) $DEVICE" 2>/dev/null)" ] && {
			#ip route add 0.0.0.0/1 dev $DEVICE 2>/dev/null
			#ipset add mwan3_connected_v4 0.0.0.0/1 2>/dev/null
		}
		[ -z "$(ip route list | grep -E "128.0.0.0/1 (.*) $DEVICE" 2>/dev/null)" ] && {
			#ip route add 128.0.0.0/1 dev $DEVICE 2>/dev/null
			#ipset add mwan3_connected_v4 128.0.0.0/1 2>/dev/null
		}
	fi

Back to /etc/init.d/startvpn, look into ovpn_firewall_start( ) and find the line lan2wan_forwarding disable which I also commented to avoid that from happening in the Firewall rules.

root@GL-MT300N-V2:~# cat /etc/init.d/startvpn
. . .

ovpn_firewall_start() {
	set_ovpn_config add
	#lan2wan_forwarding disable

	uci commit firewall
	/etc/init.d/firewall reload
	# flush old connecting
	echo " "  >/proc/net/nf_conntrack
}

In my very personal setup, I do not want LAN traffic to be NATted with the OpenVPN Client IP address when traffic is going out the Tunnel, so I disabled uci set firewall.vpn_zone.masq=‘1’ line too inside the set_ovpn_config( ) function also in /etc/init.d/startvpn.

root@GL-MT300N-V2:~# cat /etc/init.d/startvpn 
. . .

set_ovpn_config() {
	local action="$1"

	if [ "$action" = "add" ]; then
		uci set firewall.vpn_zone=zone
		uci set firewall.vpn_zone.name='ovpn'
		uci set firewall.vpn_zone.input='ACCEPT' 
		uci set firewall.vpn_zone.forward='REJECT'
		uci set firewall.vpn_zone.output='ACCEPT'  
		uci set firewall.vpn_zone.network='ovpn'
		#uci set firewall.vpn_zone.masq='1'

That did the trick and it is persisten upon a device restart.

As a summary:

  • In /etc/vpn.user function ovpn_main( ) adds the 0.0.0.0/1 and 128.0.0.0/1 to the Routing Table.
  • In /etc/init.d/startvpn function ovpn_firewall_start( ) disables the LAN to WAN Firewall rule.
  • In /etc/init.d/startvpn function set_ovpn_config( ) adds the LAN to Tunnel Firewall rule including a rule with the “MASQUERADE” parameter for NAT translations in IPtables Firewall.

It is just a matter of commenting the appropriate lines for them to be ignored once the Tunnel comes UP.

With “pure Linux” commands, here are the ones which can be executed to accomplish the same thing once the OpenVPN Tunnel is UP but these will not be persistent after a re-connect of the Tunnel or a reload of the device.

root@GL-MT300N-V2:/etc/openvpn# ip route del 0.0.0.0/1
root@GL-MT300N-V2:/etc/openvpn# ip route del 128.0.0.0/1
root@GL-MT300N-V2:/etc/openvpn# iptables -A zone_lan_forward  -j zone_wan_dest_ACCEPT
root@GL-MT300N-V2:/etc/openvpn# iptables -t nat -D zone_ovpn_postrouting -m comment --comment "!fw3" -j MASQUERADE

I also have a GL-AR300M which recently got automatically upgraded to 3.024 and now has the VPN Policy-Based Routing feature available in the GL.iNET Admin Panel.
Looks like my GL-MT300N-V2 does not have the same version available (GL.iNet download center) but still not quite sure that is what would solve my scenario.

The addition of VPN Bypass available in OpenWRT to the GL.iNET Admin Panel would be good as well.
https://github.com/stangri/openwrt_packages/blob/master/vpnbypass/files/README.md

Thank you!

4 Likes

You’re doing a good job of analyzing it.

You should flash the latest testing firmware. https://dl.gl-inet.com/firmware/mt300n-v2/testing/

This works for me and saved my hair. Your solution should absolutely be part of the GUI, as it is in Redhat, Ubuntu and Suse distros… though I can see valid reasons why it is not included, but we’ve just started shipping the GL-MT300N-V2 as a solution to some ‘road warriior’ users… so that they can access their VOIP and RDP services.

It is quite common for these kind of users to only be provided with limited access to internal subnets - with no route to the internet apart from what they already have (from their default route provided by their home/hotel/mobile connections).

I can report that it works also on 3.0.25 on a “Slate” device too ( GL-AR750S).

Thanks Gustavo!

I’m glad to read it was useful!
Cheers.

A quick note to pass on my appreciation – thank you for a very clear, comprehensive and easy-to-follow explanation, Gustavo !

I had found the vpn.user script and commented out the route adds, but I had not picked up on the firewall update to block WAN traffic. That explains a lot :slight_smile:

Thanks again!
Sean

PS - GL-Inet guys - it would be SO NICE to have this as a tick-box in Luci :slight_smile:

Thanks for sharing. Two things:

  1. Use vpn only to access some network. Can you use vpn policies to achieve this? Of course this is not that automatic as pushing route from the openvpn server. But it should work for your case.

  2. Can you use our S2S solution? Site-to-Site Network - GL.iNet
    We used wireguard and everything is configured from the cloud. Your data will go to normal network if you don’t configure routing.
    You need two GL.iNet router for this purpose.

While coming back to your scenario, can you clarify that this is the requirements:

  • When setting UP VPN client connection, provide an option “Router all traffic to VPN”. If ticked, it will be like the default firmware as in 3.013-3.027. If not ticked, VPN tunnel will be built and firewall rules is not changed.
  • Accept route push option from openvpn server.

While coming back to your scenario, can you clarify that this is the requirements:

  • When setting UP VPN client connection, provide an option “Router all traffic to VPN”. If ticked, it will be like the default firmware as in 3.013-3.027. If not ticked, VPN tunnel will be built and firewall rules is not changed.
    [gustavo86] Yes if “Route all traffic to VPN” option is not ticked, the result should be:
  1. VPN tunnel will be built
  2. Firewall rules are not changed
  3. Default static routes are NOT added (no 0.0.0.0/1 and 128.0.0.0/1 in the ‘route -n’ output)
  • Accept route push option from openvpn server.
    [gustavo86] Yes.

Alzhao,

Sorry for the delay in coming back to the forum, but the S2S solution would not work for us as we have a dedicated system that builds the configurations etc for end users. The end user just connect to their own corporate networks via a dedicated tunnel that they have to us - or directly into their own cloud systems, also hosted by us.

Has this been implemented into official firmware? Just checking :wink:
thanks - Patrick

I completely agree with this. That would be very nice. I just followed these steps with a new GL-AR750S I just got (I updated the firmware to the latest, which is currently 3.101) and it works! Thanks so much for documenting this!

I need to do some more testing, but I may be setting up and deploying several of these for my team so we can work more effectively from home during the coronavirus. Having an option in the UI to allow VPN and internet access would be great!

1 Like

What should be the default?

I’m guessing more people use VPNs in situations where they want all traffic going through them, but I’m not sure.

I think the default should be to accept what the server is sending, with options to override it either way: if the server pushes a default route the client should be able to ignore that and if the server doesn’t push a default route the client should be able to install one anyway. If no option is selected, honor the server’s push (or lack thereof.)

What should be the default?

I couldn’t care less but wait a sec, while you’re at it… it would be in general nice if one could for example setup a wireguard connection / tor / ovpn and set up shadowsocks / tor / at the same time, so that not all of these fall under “VPN is already connected connect”, especially if you’re on one a client only and want to make another connection where you would be the host, but a default and non-default, slider should do the trick for “all” of us? As it seems.

This really helped a lot. My config file worked to do this with DDWRT and OpenWRT but not on the gl.inet. This fixed my issue. How is this thread this old and this is still not implemented? This is such a common thing I feel like. It sucks when you upgrade the firmware that you have to recomment this stuff out.

Don’t know what you mean. Split tunnel?

This has been implemented in the firmware as vpn policy for a long time.

Hmm. I mean having my internet traffic go out the local WAN but being able to access a LAN over the VPN. The VPN policy just allows specific things across the VPN. I haven’t found a way other than this to accomplish that.

I’ve just re-discovered these posts since I’ve upgraded several devices and been struck by the same problem, as it has rewritten the original configuration.

I’m surprised that this still a problem!

From my testing this is no longer a solution as both the /etc/init.d/startvpn and /etc/vpn/user files have changed significantly from 3.1 to 3.2.

Creta, Slate, and Puli devices no longer work for us.

I’ve reverted the both the Creta and the Slate devices, but the Puli’s firmware starts at 3.2.

What is the solution?

Alzao, the default should be accepting push from the server. Otherwise service providers will be forced to remotely connect to customer devices and adjust them. If someone upgrades a unit, then the changes are lost. There has to be a better way surely?

Perhaps the solution should be linked to the physical switch - ie “enable server push”?

Thanks in advance - Patrick

Starting with 4.x firmware, VPN will support server push and custom routes.