OpenWrt Forum Archive

Topic: Script help: launch OpenVPN from a ssh reverse tunnel

The content of this topic has been archived on 7 Apr 2018. There are no obvious gaps in this topic, but there may still be some posts missing at the end.

I have the following issue with using a tunnelled ssh connection to launch a VPN on a very recent CC install:

- on boot, autossh runs to make a tunnel to a remote server [working]
- I can log in to the router via the tunnel [working]
- launch OpenVPN [working]
- have autossh reconnect to the remote server via the VPN [not working]
- exit the VPN [not working]
- have the tunnel brought back up via wan  [not working]

This means that once I start the VPN I am locked out of my router.

It seems that the existing ssh/autossh processes aren't killed properly on openvpn start, meaning the port is held on the remote server. By trial and error I found that the following sequence of commands (issued on a local test system) issued one after an other achieves what I want:

/etc/init.d/autossh stop   [kills the existing ssh sessions to the remote server]
/etc/init.d/openvpn start
/etc/init.d/autossh start   [starts a new instance of ssh and connects to the remote server]
#use the VPN connection as normal.
#when done
/etc/init.d/autossh stop
/etc/init.d/openvpn stop
/etc/init.d/autossh start 

How can I put all this in a script so I can issue, e.g., '/etc/init.d/customVPN start' remotely to bring up the VPN and be able to log back in via the 'new' ssh tunnel?

And then, when done with the VPN, issue '/etc/init.d/customVPN stop' to bring back up a tunnel over WAN?

I've tried issuing '/etc/init.d/openvpn start' using openVPN's 'up' parameter, but that seems to be too early in the sequence. There is no pre-up parameter to allow '/etc/init.d/openvpn stop'. However, there is pre-down to issue '/etc/init.d/openvpn stop' before openVPN stops.

Would hotplug.d scripts work? It seems there is an autossh script already that is meant to run when an interface is brought up, but that doesn't seem to be working...

All help / ideas greatly appreciated.

A tunnel, in a tunnel. You are asking for trouble... What is The purpose of this config? You sure this the most elegant and efficient way to do what you want to do?

w1zz4 wrote:

What is The purpose of this config? You sure this the most elegant and efficient way to do what you want to do?

The issue is that the router is behind CGNAT (a 4G dongle). To get in to it remotely I've been using autossh get a tunnel set-up to a remote server. This works well so far to help with editing configurations etc. and get to LAN devices.

For the devices behind the router, I'm using a VPN connection to try and avoid double NAT. I'd like to able to bring this connection up and down as required. Hence the need to use the 1st tunnel to initiate the VPN connection. Then have a new tunnel over the VPN to be able to stop it.

If there is another way to achieve this? ie. can the 1st tunnel remain operational with the VPN operating concurrently?

I will promptly use double NAT over double encryption If I was you.

To solve the issue,You could use a more basic VPN like pptp since encryption is not problem (ssh is already encrypted). you could also host the vpn on the other side and use your router as the client.

If you let the CGNAT connect directly to the server using OpenVPN...

...and if the connection goes down you let the CGNAT automatically reconnect OpenVPN, that is not complicated...

Why do you need to bring it down? You anyway need to keep the SSH up in your case?

If you want to "bring it down" just stop routing traffic from "behind the router" over VPN, and the VPN will allow you to ssh into the CGNAT to start routing again.

Not sure I follow or maybe it isn't possible. To be clear, I only use the reverse tunnel for ssh access as there is no public IP available and I am physically remote. No traffic is routed along it.

(1) LAN devices --- [ eth0 | OpenWRT | wwan0 ] -------> outside

switchable to

(2) LAN devices --- [ eth0 |   OpenWRT  | wwan0 ] - - - - - 
                            VPN client  | vpn0  ] <-----> [ VPN server ] <---->  outside

The key thing is stability due to the lack of physical access to the router. (1) is stable enough (power cycle to fix usually). With (2) you'd be relying on the VPN always working; using a 3rd party service is proving to be hit and miss with dropped connections at peak times etc.

So, to have (1) always available to fall back to if (2) goes down would be advantageous.

I can set this up successfully by issuing the commands in the OP from the LAN-side. I can't do it remotely as the connection would drop as vpn0 comes up and takes over. Hence the need for a script to do it via init.d or hotpug.d, or a combination of the two.

zo0ok wrote:

If you want to "bring it down" just stop routing traffic from "behind the router" over VPN, and the VPN will allow you to ssh into the CGNAT to start routing again.

Ahh, I think I get what you mean...

Have the VPN come up on boot, but not the routing part.

That way autossh can connect out and make the tunnel over the non-VPN gateway. Then the routing can be altered for the LAN devices to use vpn0?

Is that what you mean?

tristanc wrote:
zo0ok wrote:

If you want to "bring it down" just stop routing traffic from "behind the router" over VPN, and the VPN will allow you to ssh into the CGNAT to start routing again.

Ahh, I think I get what you mean...

Have the VPN come up on boot, but not the routing part.

That way autossh can connect out and make the tunnel over the non-VPN gateway. Then the routing can be altered for the LAN devices to use vpn0?

Is that what you mean?

If you like it, it is what I mean wink

Your CGNAT has a non-public-ip, and behind it are several machines that you want to be able to access.
What you do have is a "server" with a public IP.
Today you let CGNAT make an autossh-connection to this "server", and through the reverse SSH-tunnel you can access the CGNAT and even set up VPN (between CGNAT and server).

My point is... if you can establish an SSH connection from CGNAT to server... what prevents you from directly establishing an OpenVPN-connection from CGNAT to server instead? Even though I love reverse SSH-tunnels, I think you will be able to do everything you want using OpenVPN directly.

(Last edited by zo0ok on 28 Feb 2015, 10:15)

zo0ok wrote:

My point is... if you can establish an SSH connection from CGNAT to server... what prevents you from directly establishing an OpenVPN-connection from CGNAT to server instead? Even though I love reverse SSH-tunnels, I think you will be able to do everything you want using OpenVPN directly.

Hmm, OK. I agree, I could have the VPN come up on boot and then use the public IP to access the router over ssh (with appropriate keys). A minor point, my remote server is not the same machine running the VPN and I'll have to implement this on a physically remote router that _has_ to come back up!

I just can't understand why starting the VPN stops autossh working. The hotplug.d file indicates that when an interface comes up (vpn0 in this case) that autossh should restart and, I assume, should then use the VPN connection to access my server.

I don't think this happens as, perhaps, the previous tunnels may not have been closed properly. Therefore I can't 'reuse' the ports until they've timed-out.

My attempts this morning to put in a script how I get it to work with manual commands is hitting a dead end...

tristanc wrote:

I just can't understand why starting the VPN stops autossh working.

...wait... I didn't understand you got this particular problem until now...

When OpenVPN starts, it knows the address of the server, and it "protects" the routing to that address from being subject to VPN routing. But if you run VPN over a tunnel (i.e. connect to a VPN server that appears to run on localhost) then OpenVPN does not know how to protect the routing of SSH traffic to the other SSH node.

Your VPN-traffic is routed through the SSH tunnel.
But as soon as VPN comes up, SSH traffic is routed through VPN.

Am I correct?

zo0ok wrote:

When OpenVPN starts, it knows the address of the server, and it "protects" the routing to that address from being subject to VPN routing. But if you run VPN over a tunnel (i.e. connect to a VPN server that appears to run on localhost) then OpenVPN does not know how to protect the routing of SSH traffic to the other SSH node.

Your VPN-traffic is routed through the SSH tunnel.
But as soon as VPN comes up, SSH traffic is routed through VPN.

Am I correct?

No. No traffic is routed through the SSH tunnel. Everything goes through the default GW (4G modem's config). I merely use autossh to automatically start a reverse tunnel to the server on boot, initiated from the router, so I can get in from the server back down the tunnel. The VPN obviously changes all the routing when it starts up, and I need the existing tunnel to be closed properly so I can use the port again.

I have been working on using a combination of init.d script and hotplug.d, along with up and down openvpn scripts with some success. I'll post this in a few minutes once I've cleaned it up.

So the process is:

1) Router boots and autossh creates tunnel to remote server
2) I connect to this tunnel to manage the router
3) I want to be able to issue a command (/etc/init.d/vpn start) to start a VPN client connection (to StongVPN) to avoid doubleNAT on the LAN-connected clients. The command needs to be issued by ssh'ing in to the router from the server - using the tunnel.
3a) Before the VPN is initiated, autossh needs closed cleanly to release the port(s) used on the server.
4) When the VPN is up, I can access the router via the public IP of the VPN server.
5) I'd ALSO like to have autossh run when the VPN is up to connect to the server as in (1) and the router be reachable via that route, so autossh needs to run after the VPN is up.
6) When the VPN is stopped, autossh needs to stop cleanly first, then the VPN goes down, then autossh needs to start again using the normal routing / gateway.

To achieve this, I have used 4 scripts (A to D) inspired by https://forum.openwrt.org/viewtopic.php … 21#p105621 Next to them I have indicated the order they are run in.

A init.d/vpn
- to kill any existing autossh instances (1)
- to run /etc/init.d/openvpn start (2)
- to kill the VPN autossh instance (4)
- to run /etc/init.d/openvpn stop (5)

B hotplug.d/iface/60-vpnscript
- to run /etc/init.d/autossh start  on ifup (3) and ifdown (6) of the VPN interface vpn0

C /etc/openvpn/autossh-up.sh (3)
D /etc/openvpn/autossh-down.sh (6)
- scripts run from openvpn on Up / Down to initiate the hotplug.d

$ cat /etc/init.d/vpn
#!/bin/sh /etc/rc.common
# Example script
# Copyright (C) 2007 OpenWrt.org
 
START=90
STOP=90
 
start() {        
        logger "VPN: init.d script start"
    /etc/init.d/autossh stop
        logger "VPN: autossh stopped over WAN"
    /etc/init.d/openvpn start
        logger "VPN: openvpn started"
}                 
 
stop() {          

        logger "VPN: init.d script stop"
    /etc/init.d/autossh stop
        logger "VPN: autossh stopped over VPN"
    /etc/init.d/openvpn stop
        logger "VPN: openvpn stopped"
}
$ cat /etc/hotplug.d/iface/60-vpnscript 
#!/bin/sh

if [ "$INTERFACE" = "vpn0" ] && [ "$ACTION" = "ifup" ]
#if [ "$DEVICE" = "tun0" ] && [ "$ACTION" = "ifup" ]

then
        /etc/init.d/autossh start
    logger "VPN: autossh start over VPN"
fi

if [ "$INTERFACE" = "vpn0" ] && [ "$ACTION" = "ifdown" ]
#if [ "$DEVICE" = "tun0" ] && [ "$ACTION" = "ifdown" ]

then
        /etc/init.d/autossh start
    logger "VPN: autossh start over WAN"
$ cat /etc/openvpn/autossh-up.sh 
#! /bin/sh

ACTION=ifup INTERFACE=vpn0 /sbin/hotplug-call iface

exit 0
$ cat /etc/openvpn/autossh-down.sh 
#! /bin/sh

ACTION=ifdown INTERFACE=vpn0 /sbin/hotplug-call iface

exit 0

My /etc/config/openvpn looks like:

$ cat /etc/config/openvpn
config openvpn 'myvpn'
    option _description 'StrongVPN settings'
    option _role 'client'
    option dev 'tun'
    option proto 'udp'
    option log '/tmp/openvpn.log'
    option ca '/etc/openvpn/ca.crt'
    option cert '/etc/openvpn/my-vpn.crt'
    option key '/etc/openvpn/my-vpn.key'
    option client '1'
    option echo 'vpnXXXXXXX'
    option nobind '1'
    option persist_tun '1'
    option persist_key '1'
    option tun_mtu '1500'
    option remote '109.XXXXXXXXX'
    option redirect_gateway 'def1'
    option cipher 'AES-128-CBC'
    option hand_window '30'
    option reneg_sec '86400'
    option resolv_retry 'infinite'
    option route_delay '2'
    option comp_lzo 'no'
    option port '4672'
    option verb '4'
    option mssfix '1390'
    option fragment '1390'
    option pull '1'
    option tls_auth '/etc/openvpn/ta.crt 1'
    option up_restart '1'
    option up '/etc/openvpn/autossh-up.sh'
    option down '/etc/openvpn/autossh-down.sh'
    option enabled '1'
    option script_security '2'

This 'works' apart from a dropbear error "authpriv.info dropbear[13979]: Exit before auth: Exited normally" when I try to connect to the running ssh tunnel over the VPN...

16:47:20 user.notice root: VPN: init.d script start
16:47:20 user.info autossh[14405]: received signal to exit (15)
16:47:20 user.notice root: VPN: autossh stopped over WAN
16:47:20 user.notice root: VPN: openvpn started
16:47:23 daemon.notice netifd: Interface 'vpn0' is enabled
16:47:23 daemon.notice netifd: Network device 'tun0' link is up
16:47:23 daemon.notice netifd: Interface 'vpn0' has link connectivity 
16:47:23 daemon.notice netifd: Interface 'vpn0' is setting up now
16:47:24 daemon.notice netifd: vpn0 (15453): udhcpc (v1.22.1) started
16:47:24 user.info autossh[15460]: starting ssh (count 1)
16:47:24 user.info autossh[15460]: ssh child pid is 15464
16:47:24 daemon.notice netifd: vpn0 (15453): Sending discover...
16:47:24 user.notice firewall: Reloading firewall due to ifup of vpn0 ()
16:47:25 user.notice root: starting ntpclient
16:47:26 user.notice root: VPN: autossh start over VPN
16:47:27 daemon.notice netifd: vpn0 (15453): Sending discover...
16:47:30 daemon.notice netifd: vpn0 (15453): Sending discover...
16:48:35 authpriv.info dropbear[15730]: Child connection from 127.0.0.1:39165
16:48:35 user.info autossh[15460]: ssh exited with error status 1; restarting ssh
16:48:35 user.info autossh[15460]: starting ssh (count 2)
16:48:35 user.info autossh[15460]: ssh child pid is 15735
16:48:35 authpriv.info dropbear[15730]: Exit before auth: Exited normally

From here, I can't access from the remote server and have to run /etc/init.d/autossh restart to get it back up.

For completeness, here is the output of /etc/init.d/vpn stop

16:54:33 user.notice root: VPN: init.d script stop
16:54:33 user.info autossh[15460]: received signal to exit (15)
16:54:33 user.notice root: VPN: autossh stopped over VPN
16:54:33 user.notice root: VPN: openvpn stopped
16:54:33 daemon.notice netifd: Network device 'tun0' link is down
16:54:33 daemon.notice netifd: Interface 'vpn0' has link connectivity loss
16:54:33 daemon.notice netifd: vpn0 (15453): Read error: Network is down, reopening socket
16:54:33 daemon.notice netifd: Interface 'vpn0' is disabled
16:54:33 daemon.notice netifd: vpn0 (15453): udhcpc: bind: No such device
16:54:33 user.notice root: stopping ntpclient
16:54:33 user.notice root: VPN: autossh start over WAN
16:54:33 user.info autossh[16670]: starting ssh (count 1)
16:54:33 user.info autossh[16670]: ssh child pid is 16672

Any ideas? Could it be the timing of the ifup command? Or is it the autossh hotplug script interfering?

(Last edited by tristanc on 28 Feb 2015, 17:56)

Still looking for some help with this, but found a reasonable workround in the meantime.

I've removed the autossh instances over VPN. I just couldn't get it to come up reliably. So instead I'll use the Public IP to connect using keys only.

Oh, and another thing that may flummox people in the future: if logged in remotely call the vpn script with nohup and put it in the background:

$ nohup /etc/init.d/vpn start &

The discussion might have continued from here.