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 (https://dl.gl-inet.com/firmware/mt300n-v2/v1/) 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.

Thank you!

2 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.