Introduction
I was looking for a project to learn how to use the GPIO on the raspberry pi, and started with an adafruit tutorial on checking mail and turning on LEDs. Since I get too much email, I decided to change the application to check for sucessful and failed ssh attempts on the rpi.
I learned some nifty things about processing files in python using generators, or streams.
ssh logs successful and failed attempts to /var/log/auth.log
on the
pi.
$ grep sshd /var/log/auth.log
May 5 08:42:54 raspberrypi sshd[21479]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=humbertos-macbook.local user=pi
May 5 08:42:56 raspberrypi sshd[21479]: Failed password for pi from 10.0.1.4 port 65157 ssh2
May 5 08:43:09 raspberrypi sshd[21479]: Failed password for pi from 10.0.1.4 port 65157 ssh2
May 5 08:43:33 raspberrypi sshd[21479]: Failed password for pi from 10.0.1.4 port 65157 ssh2
May 5 08:43:33 raspberrypi sshd[21479]: Connection closed by 10.0.1.4 [preauth]
May 5 08:43:33 raspberrypi sshd[21479]: PAM 2 more authentication failures; logname= uid=0 euid=0 tty=ssh ruser= rhost=humbertos-macbook.local user=pi
May 5 08:44:10 raspberrypi sshd[21523]: Address 10.0.1.4 maps to humbertos-macbook.local, but this does not map back to the address - POSSIBLE BREAK-IN ATTEMPT!
May 5 08:44:17 raspberrypi sshd[21523]: Accepted password for pi from 10.0.1.4 port 65174 ssh2
May 5 08:44:17 raspberrypi sshd[21523]: pam_unix(sshd:session): session opened for user pi by (uid=0)
May 5 08:54:29 raspberrypi sshd[21568]: Received disconnect from 10.0.1.4: 11: disconnected by user
May 5 08:54:29 raspberrypi sshd[21523]: pam_unix(sshd:session): session closed for user pi
May 5 08:54:34 raspberrypi sshd[23682]: Accepted publickey for pi from 10.0.1.4 port 65320 ssh2
May 5 08:54:34 raspberrypi sshd[23682]: pam_unix(sshd:session): session opened for user pi by (uid=0)
May 5 08:54:48 raspberrypi sshd[24935]: Received signal 15; terminating.
May 5 08:54:48 raspberrypi sshd[23682]: pam_unix(sshd:session): session closed for user pi
May 5 08:55:07 raspberrypi sshd[2215]: Server listening on 0.0.0.0 port 22.
May 5 08:55:12 raspberrypi sshd[2215]: Received signal 15; terminating.
May 5 08:55:12 raspberrypi sshd[2292]: Server listening on 0.0.0.0 port 22.
May 5 08:56:16 raspberrypi sshd[2300]: Accepted publickey for pi from 10.0.1.4 port 65336 ssh2
May 5 08:56:16 raspberrypi sshd[2300]: pam_unix(sshd:session): session opened for user pi by (uid=0)
May 5 18:37:28 raspberrypi sshd[2300]: pam_unix(sshd:session): session closed for user pi
May 6 13:11:00 raspberrypi sshd[5331]: Accepted publickey for pi from 10.0.1.4 port 57060 ssh2
May 6 13:11:00 raspberrypi sshd[5331]: pam_unix(sshd:session): session opened for user pi by (uid=0)
It looks like no matter the method of authentication, we can just check for sshd logs that say "Failed" or "Accepted".
Methods
Following the tutorial on blinking leds, I constructed a circuit with a red LED on pin 23 on the pi, and a green LED on pin 18.
We can set up code to initialize the leds to off, and to blink a specified led.
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GREEN_LED = 18
RED_LED = 23
GPIO.setup(GREEN_LED, GPIO.OUT)
GPIO.setup(RED_LED, GPIO.OUT)
GPIO.output(RED_LED, False)
GPIO.output(GREEN_LED, False)
def blink_led(led):
GPIO.output(led, True)
time.sleep(1.0)
GPIO.output(led, False)
We're going to use python generators to produce a /stream/, an infinite
list of sshd log entries from /var/log/auth.log
. If these lines
match "Failed" we blink the red LED, if they match "Accepted", we
blink the green LED.
def follow(thefile):
thefile.seek(0,2) # Go to the end of the file
while True:
line = thefile.readline()
if not line:
time.sleep(0.1) # Sleep briefly
continue
yield line
if __name__ == "__main__":
log = open("/var/log/auth.log")
lines = follow(log)
lines = (line for line in lines if "sshd" in line)
for line in lines:
if "Failed" in line:
blink_led(RED_LED)
if "Accepted" in line:
blink_led(GREEN_LED)
GPIO.cleanup()
Results
This program loops forever, waiting for ssh login attempts and blinking the appropriate LED.
Discussion
I like the program, and python generators are a lot cooler than I thought.