Monitor login attempts on your home WiFi

Infinite Future

The infinite loop in lines 28-40 of Listing 2 checks the DHCP lease file on the router every 30 seconds to discover whether the list with the MAC addresses extraced using the cut command results in a different sha1sum footprint than the previous run. To maintain that value even through a reboot, line 36 stores the current value in the router's non-volatile RAM using nvram set. nvram get in line 31 picks the value up again to compare it with the current value from the lease file and transfers the current file to the server in case of changes.

To make sure the router runs the script after every reboot, I dropped it in the web UI in the Startup text field below Administration | Commands and pressed the Save Startup button at the bottom of the page (Figure 3). If something goes wrong, it isn't easy to discover why; the slimmed down commands on DD-WRT do not provide very much in the way of detailed error messages, but if you log in to the router using SSH and run the script manually at the command line, you can normally find the culprit.

Figure 3: This script periodically sends changed lease entry files to the server.


The router thus ensures that the current version of the lease file is always available on a Linux server where a cron job,

* * * * * /home/perlsnapshot/lease-notify

running once a minute, detects the changes and notifies the Prowl web service about events, like clients joining or leaving the WiFi.

The Prowl service requires users to register on the Prowl website [2] with a username and password, where you do not need to provide an email address; however, it is useful later if you forget your password. An account entitles you to obtain API keys with which applications that want to send events authenticate against the web service. The Prowl server forwards the text messages to all instances of the app registered under the account. The app costs $2.99 for an iPhone, but registering on the website to pick up an API key and forwarding the push notifications are both free for up to 1,000 events sent per day.

Link If Needed

The simple test included in Listing 3 shows the procedure that uses the CPAN WebService::Prowl module, which nicely abstracts access to the Prowl web service. It requires an API key, which is available on the website under the API Keys tab as a text string for the logged-in user (Figure 4). The verify() method in line 8 checks whether communication to the Prowl server is working, and the add() method in line 10 accepts the four text strings for the message to be sent over the air.

Listing 3


01 #!/usr/local/bin/perl -w
02 use strict;
04 use WebService::Prowl;
05 my $ws = WebService::Prowl->new(
06     apikey => "xxxxxxxxxxxxxxxxxxxxxxx");
08 $ws->verify || die $ws->error();
10 $ws->add(
11     application => "Perl Snapshot",
12     event       => "Just a test.",
13     description => "Huzzah, it works!",
14     url         => "",
15 );
Figure 4: Free API keys from Prowl.

The first three parameters provide the name of the sending application, the type of event, and a short description. The fourth parameter, url, carries a URL that the cell phone is supposed to access when the user taps on the event and then consents to launching the browser. In Figure 5, you can see the push notification for the test event from Listing 3 just arriving on my locked iPhone 5. Figure 6 shows the dialog that appears when the user taps on the event.

Figure 5: The iPhone showing the test message on the lock screen.
Figure 6: Opening the URL for the event.

On the server side, the script in Listing 4 runs as a cron job. It maintains a persistent data repository in the leases.dat file, to which it binds the %leases hash in line 14 using tie. After lease-notify is launched, the program looks for a file named dnsmasq.leases, loads its data using the CPAN Path::Tiny module, and then iterates through its text with lines() in line 20. The split() function in line 22 breaks down the space-separated fields into the remaining lease duration, MAC address, issued IP address, and device name.

Listing 4


01 #!/usr/bin/perl -w
02 use strict;
03 use lib '/home/perlsnapshot/perl5/lib/perl5';
04 use Path::Tiny;
05 use DB_File;
06 use WebService::Prowl;
07 use File::Basename;
09 my $in_file  = "dnsmasq.leases";
10 my $db_file  = "leases.dat";
11 my $API_KEY  = "xxxxxxxxxxxxxxxxxxxxxxx";
12 my $APP_NAME = "Wifi watch";
14 tie my %leases, 'DB_File', $db_file;
16 my $file  = path( $in_file );
18 my %found = ();
20 for my $line ( $file->lines ) {
21   my( $secs, $mac, $ip, $name ) =
22       split " ", $line;
24   $found{ $mac } = 1;
26   if( !exists $leases{ $mac } ) {
27     $leases{ $mac } = "$ip $name";
28     notify( "joined: $leases{ $mac }" );
29   }
30 }
32 for my $mac ( keys %leases ) {
33   if( !exists $found{ $mac } ) {
34     notify( "left: $leases{ $mac }" );
35     delete $leases{ $mac };
36   }
37 }
39 untie %leases;
41 ###########################################
42 sub notify {
43 ###########################################
44   my( $event ) = @_;
46   my $ws = WebService::Prowl->new(
47       apikey => $API_KEY );
49   $ws->verify || die $ws->error();
51   $ws->add(
52       application => $APP_NAME,
53       event       => $event,
54       description => "Home Wifi clients",
55       url         => "",
56   );
57 }

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus

Direct Download

Read full article as PDF:

Price $2.95