Monday, August 29, 2016

Raspberry pi experiment - ssh reverse tunnel with a public server

Background

I wanted to access my Raspberry Pi from anywhere possible but had issue with how to do it without setting up a static IP or tinkering the ISP routing table. While exploring for the solution I can across SSH reverse proxy. This blog post explores my experiences with setting it up a reverse proxy from Raspberry PI to a AWS server through which I can access using a public AWS IP address.

What is ssh reverse tunnel?



The above image will give a fair bit of idea as to what is Reverse SSH tunnel and what I am trying to achieve. SSH is very good tool to access remote machine or server securely. But, the problem arises when you try to connect to a remote server which is behind a firewall/nat and this firewall/nat denies any incoming connection or data transfer request that has no prior outgoing request. This means that only those connections would be allowed which are initiated by the remote server machine. This is a real problem for those who want to access this server machine remotely.

Reverse SSH provides a technique through which you can simulate a normal SSH to this remote server machine.

The main problem is that firewall is rejecting ssh connection that your machine is trying to establish with remote server machine. But you know that the same firewall will not have any problem with the connections originating from server machine. So, why not ask some one who is sitting behind the firewall to do something with which you can achieve your goal of remotely accessing the server. To do this we have to use ssh -R option.

Let's assume that Destination's IP is 192.168.20.55 (Linux box that you want to access).
You want to access from Linux client with IP 138.47.99.99.
Destination (192.168.20.55) <- |NAT| <- Source (138.47.99.99)
1. SSH from the destination to the source (with public ip) using command below:
ssh -R 19999:localhost:22 sourceuser@138.47.99.99
* port 19999 can be any unused port.
2. Now you can SSH from source to destination through SSH tuneling:
ssh localhost -p 19999
3. 3rd party servers can also access 192.168.20.55 through Destination (138.47.99.99).
Destination (192.168.20.55) <- |NAT| <- Source (138.47.99.99) <- Bob's server
3.1 From Bob's server:
ssh sourceuser@138.47.99.99
3.2 After the sucessful login to Source:
ssh localhost -p 19999
* the connection between destination and source must be alive at all time.
Tip: you may run a command (e.g. watch, top) on Destination to keep the connection active.
At this juncture I came to a problem where when ever I was doing a remote tunnel to my aws server via ssh command it was also opening a session which I did not want. I basically wanted a service to run in background. I also installed auto ssh but there also I faced issues. Hence I rolled my own solution for running a reverse proxy tunnel which I will be covering below.

Rtunnel - Reverse proxy service for Raspberry pi



The basis of this script is paramiko python library which is the leading native sshv2 python library. I used the code from rforward.py as the basis for my python script rtunnel.py . And made some changes to extract the logs of rtunnel service to /tmp/rtunnel.log. Which can as a stand alone script in itself.

Additionally I have created a script rtunnel.sh which helps to convert rtunnel.py as a Raspberry pi init.d service.

Installation

First install the below packages:

sudo apt-get install build-essential libssl-dev libffi-dev python-dev

The easiest way to install is to clone the repo from github to raspberry pi
git clone https://github.com/bobquest33/rtunnel_devel.git
cd  rtunnel_devel
pip install -r requirement.txt
Test if rtunnel.py works
 python rtunnel.py -u ubuntu -K Priyabratadash1.pem -p 8001 -r 127.0.0.1:8001 e2host.compute.amazonaws.com

Some of the options for the rtunnel.py is given below which you can find in rtunnel.log when you run python rtunnel.py -h:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -q, --quiet           squelch all informational output
  -p PORT, --remote-port=PORT
                        port on server to forward (default: 4000)
  -u USER, --user=USER  username for SSH authentication (default: pridash4)
  -K KEYFILE, --key=KEYFILE
                        private key file to use for SSH authentication
  --no-key              don't look for or use a private key file
  -P, --password        read password (for key or password auth) from stdin
  -r host:port, --remote=host:port
                        remote host and port to forward to
Copy rtunnel_devel folder to /usr/local/bin:
sudo cp -r rtunnel_devel /usr/local/bin/rtunnel


Setting Rtunnel Service:

The following init script makes getting a Python script (or e.g. a Perl script) to run when the Raspberry Pi boots fairly painless. Services are supposed to run as “daemons” which is quite complicated in Python and involves forking the process twice and other nasty bits. 
Instead we can make use of the handy start-stop-daemon command to run our script in the background and basically deals with everything we need.

While setting the script rtunnel.sh please make the following changes to reflect the correct options of rtunnel.py


SSH_USER=ubuntu
KEY_FILE=$DIR/Priyabrata1.pem
SSH_SERVER=ec2host.compute.amazonaws.com
REMOTE_FWD_HOST=127.0.0.1:8001
LOCAL_PORT=8001


The code for rtunnel.sh is give below. For latest version please refer to the github link:




































































#!/bin/sh
### BEGIN INIT INFO
# Provides: rtunnel
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: This service helps to access a local port from a remote server & port
# Description: This service helps to access a remote port from a remote server & port
### END INIT INFO
# Change the next 3 lines to suit where you install your script and what you want to call it
DIR=/usr/local/bin/rtunnel
DAEMON=$DIR/rtunnel.py
DAEMON_NAME=rtunnel
SSH_USER=ubuntu
KEY_FILE=$DIR/Priyabrata1.pem
SSH_SERVER=<ec2_host>.compute.amazonaws.com
REMOTE_FWD_HOST=127.0.0.1:8001
LOCAL_PORT=8001
# Add any command line options for your daemon here
DAEMON_OPTS="-u $SSH_USER -K $KEY_FILE -p $LOCAL_PORT -r $REMOTE_FWD_HOST $SSH_SERVER"
# This next line determines what user the script runs as.
# Root generally not recommended but necessary if you are using the Raspberry Pi GPIO from Python.
DAEMON_USER=root
# The process ID of the script when it runs is stored here:
PIDFILE=/var/run/$DAEMON_NAME.pid
. /lib/lsb/init-functions
do_start () {
log_daemon_msg "Starting system $DAEMON_NAME daemon"
start-stop-daemon --start --background --pidfile $PIDFILE --make-pidfile --user $DAEMON_USER\

--chuid $DAEMON_USER --startas $DAEMON -- $DAEMON_OPTS
log_end_msg $?
}
do_stop () {
log_daemon_msg "Stopping system $DAEMON_NAME daemon"
start-stop-daemon --stop --pidfile $PIDFILE --retry 10
log_end_msg $?
}
case "$1" in
start|stop)
do_${1}
;;
restart|reload|force-reload)
do_stop
do_start
;;
status)
status_of_proc "$DAEMON_NAME" "$DAEMON" && exit 0 || exit $?
;;
*)
echo "Usage: /etc/init.d/$DAEMON_NAME {start|stop|restart|status}"
exit 1
;;
esac
exit 0



Using the init script


To actually use this script, put your Python script where you want and make sure it is executable (e.g. chmod 755 rtunnel.py) and also starts with the line that tells the computer to use the Python interpreter (e.g. #!/usr/bin/env python). Edit the init script accordingly. Copy the init script into /etc/init.d using e.g. sudo cp rtunnel.sh /etc/init.d. Make sure the script is executable (chmod again) and make sure that it has UNIX line-endings (dos2unix).
To make the Raspberry Pi use your init script at the right time, one more step is required: running the command sudo update-rc.d rtunnel.sh defaults. This command adds in symbolic links to the /etc/rc?.d directories so that the init script is run at the default times. you can see these links if you do ls -l /etc/rc?.d/*rtunnel.sh

At this point you should be able to start your Python script using the command sudo /etc/init.d/rtunnel.sh start, check its status with the /etc/init.d/rtunnel.sh status argument and stop it with sudo /etc/init.d/rtunnel.sh stop.

Troubleshooting

There are a lot of things to get right here. Here are some things to check (with thanks to David Selinger):
  1. Make sure your Python file can execute stand-alone. Make sure you can run the command sudo /usr/local/bin/rtunnel/rtunnel.py(or whatever you have called it). If that doesn’t work then check it is executable (with ls -l) and check it does not assume it is launched from a specific directory.
  2. Try the start-stop-daemon command outside of the init script. You should be able to do sudo start-stop-daemon ... with all the parameters filled in.
  3. Try writing a simple init script alternative that strips out most of the configuration and hard-codes the variables such as $DIR etc to make sure you have got that part right.
  4. Test the complete init script by hand using sudo /etc/init.d/rtunnel start (though note that you must have done the update-rc.dcommand before this).
  5. Test if it works when rebooting. If not, then you have a problem with the update-rc.d part and the /etc/rc?.d links.

Checking if the tunnel is up

In my case I was running a file server on my raspberry pi at port 8001, now to check if the public link is up I developed the above script 

#!/bin/sh #checkURL.sh
yourURL="http://<ec2_host>.compute.amazonaws.com:8001"
if curl --output /dev/null --silent --head --fail "$yourURL"
then
echo "This URL Exist"
else
echo "This URL Not Exist"
sudo service rtunnel.sh restart
fi

Finally I added a crontab entry like below to check the link every 15 mins:
*/15 * * * * sh /home/pi/bin/checkURL.sh 2>&1

Screenshots of my experiment below:

From my raspberry pi at home:



From my aws server:



Thursday, August 18, 2016

Raspberry Pi Experiments - Remote Web Cam


IMG_20160815_092029-picsay



One of my initial ideas for using Raspberry Pi was to remotely view my sons activities when ever I was away from him. So as a start I checkout my old web cam (which is a Zebatronics Ecam 2009 model) it was working and finally followed the steps in the below link to setup the webcam in my raspberry pi.
https://www.raspberrypi.org/documentation/usage/webcams/

Here I will give a brief rundown of steps that I did to setup the Web Cam.

1. Check if your web cam is a USB Webcam and the make, mine was Zebatronics Ecam 2009 model
2. Connect it to the Raspberry Pi USB port and see if the lights of the Web Cam are glowing.
3. Check if the Web Cam is detected using lsusb For me it shows the below for the webcam:
pi@raspberrypi:~ $ lsusb
Bus 001 Device 004: ID 0c45:614a Microdia


Note: The trick to know that if webcam is connected is to lsusb before and after connecting the webcam if its detected an additional USB device will show. Additionally in /dev folder check if there any device like /dev/video0

pi@raspberrypi:~ $ ls /dev/video*
/dev/video0

4. Install fswebcam and check if the webcam capture works sudo apt-get install fswebcam

pi@raspberrypi:~/webcam $ fswebcam image.jpg
--- Opening /dev/video0...                                                     
Trying source module v4l2...                                                   
/dev/video0 opened.                                                            
No input was specified, using the first.                                       
Adjusting resolution from 384x288 to 352x288.                                  
--- Capturing frame...                                                         
Captured frame in 0.00 seconds.                                                
--- Processing captured image...                                               
Writing JPEG image to 'image.jpg'.


5. Next I developed a script to capture the image and save to a folder /home/pi/webcam


mkdir /home/pi/webcam

Created a script webcam.sh


#!/bin/bash

DATE=$(date +"%Y-%m-%d_%H%M")

fswebcam -r 1280x720 --no-banner /home/pi/webcam/$DATE.jpg
 
 6. Then setup cron to capture images every minute:
 
crontab -e
 
Added this line in the editor: 
 
* * * * * /home/pi/webcam.sh 2>&1
   
7. The output can be seen as below where the script runs every one minute:
pi@raspberrypi:~ $ ls ~/webcam2016-08-18_1644.jpg 2016-08-18_1707.jpg 2016-08-18_1730.jpg2016-08-18_1645.jpg 2016-08-18_1708.jpg 2016-08-18_1731.jpg2016-08-18_1646.jpg 2016-08-18_1709.jpg 2016-08-18_1732.jpg2016-08-18_1647.jpg 2016-08-18_1710.jpg 2016-08-18_1733.jpg2016-08-18_1648.jpg 2016-08-18_1711.jpg 2016-08-18_1734.jpg2016-08-18_1649.jpg 2016-08-18_1712.jpg 2016-08-18_1735.jpg2016-08-18_1650.jpg 2016-08-18_1713.jpg 2016-08-18_1736.jpg2016-08-18_1651.jpg 2016-08-18_1714.jpg 2016-08-18_1737.jpg2016-08-18_1652.jpg 2016-08-18_1715.jpg 2016-08-18_1738.jpg2016-08-18_1653.jpg 2016-08-18_1716.jpg 2016-08-18_1739.jpg2016-08-18_1654.jpg 2016-08-18_1717.jpg 2016-08-18_1740.jpg2016-08-18_1655.jpg 2016-08-18_1718.jpg 2016-08-18_1741.jpg2016-08-18_1656.jpg 2016-08-18_1719.jpg 2016-08-18_1742.jpg2016-08-18_1657.jpg 2016-08-18_1720.jpg 2016-08-18_1743.jpg2016-08-18_1658.jpg 2016-08-18_1721.jpg 2016-08-18_1744.jpg2016-08-18_1659.jpg 2016-08-18_1722.jpg 2016-08-18_1745.jpg2016-08-18_1700.jpg 2016-08-18_1723.jpg 2016-08-18_1746.jpg2016-08-18_1701.jpg 2016-08-18_1724.jpg 2016-08-18_1747.jpg2016-08-18_1702.jpg 2016-08-18_1725.jpg 2016-08-18_1748.jpg2016-08-18_1703.jpg 2016-08-18_1726.jpg 2016-08-18_1749.jpg

8. Finally I created a script to generate a time lapse video of these images, for this first we need to install avconv which is a fork of ffmpeg.

pi@raspberrypi:~ $ sudo apt-get install avconv
Reading package lists... Done
Building dependency tree
Reading state information... Done
E: Unable to locate package avconv
Then created a script conv2vid.sh to generate the time lapse video from the images and flush the images once the video is created:


#!/bin/bash
DATE=$(date +"%Y-%m-%d_%H%M")
mv /home/pi/webcam/*.jpg /home/pi/webcam/video
cat /home/pi/webcam/video/*.jpg | avconv -r 10 -f image2pipe -codec:v mjpeg -i --pix_fmt yuvj420p -r 30 -c:v libx264 -vf scale=480:300 -y /home/pi/webcam/video/$DATE.mp4
rm /home/pi/webcam/video/*.jpg
Please find the below video for the Time lapse video

Monday, August 8, 2016

Raspberry Pi 3 Tricks - Connecting USB

Raspberry PI with 32GB Sandisk USB Stick


One of the first use cases that I found after setting up my Raspberry PI was connecting my USB Sticks. Now in home I want to access my USB flash storage stick anytime and without any issue and Raspberry PI seems to be a great way of doing it. The short steps are give below:

1. For using any standard USB stick to Raspberry Pi's USB socket
2. install pmount on Raspberry Pi using sudo apt-get install pmount
3. Use sudo fdisk -l to find your USB drive, it may be /dev/sda1
4. Mount the USB to your OS using sudo pmount /dev/sda1 it shoud mount under /media/sda1
5. After you have verified the mount and used you can unmount the USB  sudo pumount /dev/sda1
Note: Before getting the USB stick out make sure to unmount the drive.

I tried loading a 1TB hard disk but I guess it will need its own dedicated power, will post it in another post.


Terminal Cast showing how to Mount USB

Sunday, August 7, 2016

Raspberry pi 3 mod b unboxing and demo


In my latest experiment, I bought my first Raspberry PI 3 Mod B, and tried setting it up. Additionally I got a transparent casing and 16GB Sandisk Micro SD with the OS installed.

Now coming to the unboxing and setting up Raspberry PI always precision screw driver helps which I additionally bought and for power I reused one of my 5V Android mobile chargers, this type of charger is specifically suitable for Raspberry PI power requirements but 5.25 V micro usb charger is recommended. The particular case that I got from Amazon was very helpful as it was transparent and all the ports in Raspberry were readily accessible and was very easy to setup.

When I put the micro SD for some reason it did not start, hence I downloaded the latest Raspbian lite OS SD image from Raspberry website and flashed it to the Micro SD with the help of Win32Image Write on Windows. Initially I used Wired LAN to connect to Raspberry, the Wireless setup for my Raspberry I will share in a separate post. The whole process is captured in my below video.


Useful links:
Source for Raspbian OS
https://www.raspberrypi.org/downloads/raspbian/

Source for power
https://www.raspberrypi.org/help/faqs/#power

TestDriven.io: Working with Static and Media Files in Django

This article looks at how to work with static and media files in a Django project, locally and in production. from Planet Python via read...