Using Docker to Connect to Multiple VPN Networks Simultaneously (AKA Split Tunneling)

Like many of you, many people use Cisco AnyConnect to get on Enterprise Networks.

In my case, I had two separate Cisco AnyConnect networks that I needed to be connected to in order to be connected to a Virtual Desktop/Server through either RDP/SSH on each network.

As a result, I started digging into the IP Stack and seeing about ways to leverage Docker to segment route mapping and allow something like this to work to my advantage.

Here’s a rough sketch of what’s done here:

  • Step 1:
    • My Local Computer -> Spin Up Docker Container -> Have Docker Container Connect to Remote Cisco AnyConnect Endpoint
  • Step 2:
    • My Local Computer -> Allocate a local port and forward it to a remote address INSIDE the Docker Container (Destination IP/DNS and Port)
  • Step 3:
    • My Local Computer -> Open RDP/SSH Session on localhost and allocated local port -> Connection to Remote Desktop/Server Succeeded!

Now, I had a few issues getting this up and going and the major one was making sure that the OpenConnect/AnyConnect Client wasn’t effectively blocking out ssh connections to allow this port forward allocation. However, I DID end up finding a way around this and made sure that the OpenConnect/AnyConnect Client wasn’t hijacking all requests to port 22 and instead was only hijacking/redirecting requests to the VPN. I accomplished this by using a nifty tool called VPN Splice.

You can check out this awesome utility written by Dan Lenski here:

https://github.com/dlenski/vpn-slice

All in all I ended up with this great combo of work and I am extremely proud of it. It has to be the most complex little tool I think I have ever written and it would NOT be possible without the people over at Docker.

All of the below information and files can be found ready to go on my Github repo here:

https://github.com/qwertycody/Docker-VPN-Tool

Here is the Source Code (Future Updates will be on the Above Repo):

Filename: build.sh

docker rmi garrett_tech:vpn_tool --force
docker build --rm=true -t garrett_tech:vpn_tool .
docker system prune --force

Filename: Dockerfile

FROM debian:latest

RUN apt-get update 
RUN apt-get install -y openconnect
RUN apt-get install -y openssh-server 
RUN apt-get install -y passwd
RUN apt-get install -y python3
RUN apt-get install -y python3-pip
RUN apt-get install -y dnsutils
RUN apt-get install -y iptables
RUN apt-get install -y iproute2
RUN apt-get install -y screen

RUN pip3 install https://github.com/dlenski/vpn-slice/archive/master.zip

RUN apt-get clean all

RUN mkdir /var/run/sshd

RUN echo "PasswordAuthentication yes" >> /etc/ssh/ssh_config
RUN echo "PermitRootLogin yes" >> /etc/ssh/sshd_config

RUN echo 'echo "root:password" | chpasswd' >> /startup.sh
RUN echo "/usr/sbin/sshd -D &" >> /startup.sh
RUN echo "ping localhost" >> /startup.sh

EXPOSE 22
EXPOSE 3389

CMD sh /startup.sh

Filename: run_website.sh

OPENCONNECT_VPN_ENDPOINT="myCiscoVpnEndpoint.website.com"
DESTINATION_ADDRESS="myRemoteDesktopOrServerOrSshServer.website.com"
DESTINATION_PORT="3389"

LOCAL_DOCKER_ADDRESS="192.168.99.100"
LOCAL_DOCKER_SSH_PORT="2022"
LOCAL_LISTEN_PORT="2023"

CONTAINER_NAME="vpn_website"
IMAGE_NAME="garrett_tech:vpn_tool"

sh dockerVpnTool.sh $OPENCONNECT_VPN_ENDPOINT $DESTINATION_ADDRESS $DESTINATION_PORT $LOCAL_DOCKER_ADDRESS $LOCAL_DOCKER_SSH_PORT $LOCAL_LISTEN_PORT $CONTAINER_NAME $IMAGE_NAME

Filename: dockerVpnTool.sh

OPENCONNECT_VPN_ENDPOINT=$1
DESTINATION_ADDRESS=$2
DESTINATION_PORT=$3

LOCAL_DOCKER_ADDRESS=$4
LOCAL_DOCKER_SSH_PORT=$5
LOCAL_LISTEN_PORT=$6

CONTAINER_NAME=$7
IMAGE_NAME=$8

docker stop $CONTAINER_NAME
docker rm $CONTAINER_NAME

PORT_SSH="$LOCAL_DOCKER_SSH_PORT:22"

docker run -d --privileged --rm --name $CONTAINER_NAME -p $PORT_SSH $IMAGE_NAME

clear 

echo "##################################################################"
echo "THE NEXT PROMPT WILL ASK YOU TO ENTER A FEW THINGS"
echo "ONCE YOU ARE FULLY CONNECTED TO THE VPN ENDPOINT"
echo "PRESS CTRL+A+D TO DETACH AND CONTINUE THE CONNECTION PROCESS"
echo "IF YOU UNDERSTAND THESE INSTRUCTIONS PRESS ENTER TO CONTINUE"
echo "##################################################################"

read 

if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ] || [ "$(expr substr $(uname -s) 1 10)" == "MINGW64_NT" ]; then
    winpty docker exec -it $CONTAINER_NAME bash -c "screen openconnect $OPENCONNECT_VPN_ENDPOINT --script \"vpn-slice $DESTINATION_ADDRESS\""
else 
    docker exec -it $CONTAINER_NAME bash -c "screen openconnect $OPENCONNECT_VPN_ENDPOINT --script \"vpn-slice $DESTINATION_ADDRESS\""
fi

ssh-keygen -R [$LOCAL_DOCKER_ADDRESS]:$LOCAL_DOCKER_SSH_PORT
ssh -fNL $LOCAL_LISTEN_PORT:$DESTINATION_ADDRESS:$DESTINATION_PORT -l root $LOCAL_DOCKER_ADDRESS -p $LOCAL_DOCKER_SSH_PORT

echo "##################################################################"
echo "If there are no errors up to this point you can now connect"
echo "to the endpoint using localhost:$LOCAL_LISTEN_PORT using ssh/rdp"
echo "##################################################################"

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s