Workflow of the BlackBox System and Connecting in Two Steps (Python+SSH)
If you have been following this blog you probably knew that this post was coming. I have been able to use SSH and Python together with some dependencies. These dependencies are Paramiko from http://www.lag.net/paramiko/ and a python sript (which I had to edit more on that later) which was written by Zeth from http://commandline.org.uk.
In this short time using python let me say that it is a very organic programming language that should bring happiness to all programmer that have been muddling with other scripting languages. Saying that let’s go back to business.
Because I changed from Telnet to SSH some things had to change. A new design frenzy ensued. And the result was as below.
Please click on the image above to see it more clearly.
So let my explain the above flow step by step.
First of all let us first check out the dependencies. The first dependency is Paramiko. You can download it from http://www.lag.net/paramiko/. Paramiko has two dependencies. Phython and pycrypto. You can get pycrypto by using
yum install python-pycrypto*
or
yum install pycrypto
If none of the above work than you have to do it the hardware. I myself built pycrypto and paramiko myself. I used no RPM packages. For that I am proud of myself. However if you really need the rpm packages for paramiko you can find it from http://dag.wieers.com/rpm/packages/python-paramiko/.
So now you have Paramiko. However you will quickly notice that learning all the nice things that Paramiko does takes time and if you are hard-pressed on time like me you can simply download a friendly Python SSH2 interface written by Zeth from http://commandline.org.uk.
Now let’s first check this interface ;
"""Friendly Python SSH2 interface."""
"""Created by Zeth from http://commandline.org.uk"""
"""Edited by John Roach from http://johnroach.info"""
import os
import tempfile
import paramiko
import sys
class Connection(object):
"""Connects and logs into the specified hostname.
Arguments that are not given are guessed from the environment."""
def __init__(self,
host,
username = None,
private_key = None,
password = None,
port = 22,
):
self._sftp_live = False
self._sftp = None
if not username:
username = os.environ['LOGNAME']
# Log to a temporary file.
templog = tempfile.mkstemp('.txt', 'ssh-')[1]
paramiko.util.log_to_file(templog)
# Begin the SSH transport.
self._transport = paramiko.Transport((host, port))
self._tranport_live = True
# Authenticate the transport.
if password:
# Using Password.
self._transport.connect(username = username, password = password)
else:
# Use Private Key.
if not private_key:
# Try to use default key.
if os.path.exists(os.path.expanduser('~/.ssh/id_rsa')):
private_key = '~/.ssh/id_rsa'
elif os.path.exists(os.path.expanduser('~/.ssh/id_dsa')):
private_key = '~/.ssh/id_dsa'
else:
raise (TypeError, "You have not specified a password or key.")
private_key_file = os.path.expanduser(private_key)
rsa_key = paramiko.RSAKey.from_private_key_file(private_key_file)
self._transport.connect(username = username, pkey = rsa_key)
def _sftp_connect(self):
"""Establish the SFTP connection."""
if not self._sftp_live:
self._sftp = paramiko.SFTPClient.from_transport(self._transport)
self._sftp_live = True
def get(self, remotepath, localpath = None):
"""Copies a file between the remote host and the local host."""
if not localpath:
localpath = os.path.split(remotepath)[1]
self._sftp_connect()
self._sftp.get(remotepath, localpath)
def put(self, localpath, remotepath = None):
"""Copies a file between the local host and the remote host."""
if not remotepath:
remotepath = os.path.split(localpath)[1]
self._sftp_connect()
self._sftp.put(localpath, remotepath)
def execute(self, command):
"""Execute the given commands on a remote machine."""
channel = self._transport.open_session()
channel.exec_command(command)
output = channel.makefile('rb', -1).readlines()
if output:
"""This line has been added to ssh.py by John Roach"""
for line in output:
print (line.strip('n'))
"""This line has been added to ssh.py by John Roach"""
return output
else:
return channel.makefile_stderr('rb', -1).readlines()
def close(self):
"""Closes the connection and cleans up."""
# Close SFTP Connection.
if self._sftp_live:
self._sftp.close()
self._sftp_live = False
# Close the SSH Transport.
if self._tranport_live:
self._transport.close()
self._tranport_live = False
def __del__(self):
"""Attempt to clean up if not explicitly closed."""
self.close()
def main():
"""Little test when called directly."""
# Set these to your own details.
myssh = Connection('example.com')
myssh.put('ssh.py')
myssh.close()
# start the ball rolling.
if __name__ == "__main__":
main()
So you can see above what I changed. I simply added a way to get the output of any SSH command.
The other dependency for my main program is functions.py this is where I hold my functions so the main Python file can be easier to read. I don’t know if this is good practice or not in Python programming language. But I thought I looked more pleasing like this.
Hence let’s check out our functions.py file;
import os
import sys
import urllib
import re
class func(object):
def getMacAddress(self, type):
"""
This has been added by John Roach.
works in both windows and linux
Why Windows? Because I can!!!
"""
if sys.platform == 'win32':
for line in os.popen("ipconfig /all"):
if line.lstrip().startswith('Physical Address'):
mac = line.split(':')[1].strip().replace('-',':')
break
else:
for line in os.popen("/sbin/ifconfig"):
if line.find(type) > -1:
mac = line.split()[4]
break
return mac
def getIPAddress(self):
"""
This program gets your external ip
from whatismyip.com
this program must be called every
5 minutes not more or else you must
have your own server.
"""
site = urllib.urlopen("http://www.whatismyip.com/automation/n09230945.asp").read()
grab = re.findall('d{2,3}.d{2,3}.d{2,3}.d{2,3}',site)
address = grab[0]
return address
Probably need some explaining on the functions. getMacAddress
simply gets the MAC address of the embedded board. This function can work on both Windows and Linux. Why? Because I can! 😉 getIPAddress
finds out your external address. You must remember if you did the simple host trick in python you will get your LAN IP. However what I needed was the external address. So I simple steal it from www.whatismyip.com. These functions are called within the main program.
So atlast. The main program sshtry.py ;
import ssh
import functions
""" This connection is basicly to the server """
""" For testing this is basicly my desktop-computer running """
""" A special user has been created for this project with """
""" limited privilages this user is johnroach """
""" The IP of the server is IP """
s = ssh.Connection(host = 'IP, username = 'username', password = 'passowrd')
""" Calling the functions functions :) """
f = functions.func()
""" Get MAC """
"""Ethernet = eth Wi-Fi = wlan"""
mac = f.getMacAddress(type = 'wlan')
""" Get IP """
ip = f.getIPAddress()
s.execute('python getip.py '+mac+' '+ip)
s.close()
I bet you can guess what this program does. But please remember getip.py is actually in the server and is called using SSH.
So now we finished with the embedded device side of the problem. Now we have to see what happens in the server side.
The server side programs ( getipmac.py ) dependencies are different. We really don’t need SSH and we are simply going to connect to the MySQL database. For this we use a interface named MySQLdb. MySQLdb can be downloaded from http://sourceforge.net/projects/mysql-python/ or simply installed by using
yum install mysql-python
getipmac.py simply gets the MAC and IP address of the embedded device and stores it in the database. The two parameters are called when the scripts is executed. The program is as below;
import sys
import MySQLdb
if len(sys.argv)!=3:
"""the program name, mac and ip makes three"""
"""stop program and send error"""
sys.exit("Must provide mac and ip!")
mac = sys.argv[1]
ip = sys.argv[2]
try:
conn = MySQLdb.connect (host = "localhost", user = "user", passwd = "pass", db = "theblackbox")
except MySQLdb.Error, e:
print ("Error %d: %s" % (e.args[0], e.args[1]))
sys.exit(1)
cursor = conn.cursor()
cursor.execute ("""UPDATE mac_list SET ip = %s WHERE mac = %s """, (ip, mac))
print ("Number of rows updated: %d" % cursor.rowcount)
cursor.close ()
conn.commit ()
conn.close ()
Ah so we have reached the end. If you have any questions from above feel free to ask. The program works fine. Now I have to code a chat server like script in python and make it work with PHP. If you look back at the top you will see what I mean. More will come!