diff --git a/README b/README deleted file mode 100755 index aa37134..0000000 --- a/README +++ /dev/null @@ -1,202 +0,0 @@ -#!/usr/bin/perl -# -# hoover.pl - Wi-Fi probe requests sniffer -# -# Original idea by David Nelissen (twitter.com/davidnelissen) -# Thank to him for allowing me to reuse the idea! -# -# This script scans for wireless probe requests and prints them out. -# Hereby you can see for which SSID's devices nearby are searching. -# -# Copyright (c) 2012 David Nelissen & Xavier Mertens -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of copyright holders nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS OR CONTRIBUTORS -# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -# History -# ------- -# 2012/01/11 Created -# - -use strict; -use Getopt::Long; - -$SIG{USR1} = \&dumpNetworks; # Catch SIGINT to dump the detected networks -$SIG{INT} = \&cleanKill; -$SIG{KILL} = \&cleanKill; -$SIG{TERM} = \&cleanKill; - -my $uniqueSSID = 0; #uniq ssid counter -my %detectedSSID; # Detected network will be stored in a hash table - # SSID, Seen packets, Last timestamp -my $pid; -my $help; -my $verbose; -my $interface; -my $dumpFile; -my $ifconfigPath = "/sbin/ifconfig"; -my $iwconfigPath = "/sbin/iwconfig"; -my $tsharkPath = "/usr/local/bin/tshark"; -my $options = GetOptions( - "verbose" => \$verbose, - "help" => \$help, - "interface=s" => \$interface, - "ifconfig-path=s" => \$ifconfigPath, - "iwconfig-path=s" => \$iwconfigPath, - "tsharkPath=s" => \$tsharkPath, - "dumpfile=s" => \$dumpFile, -); - -if ($help) { - print <<_HELP_; -Usage: $0 --interface=wlan0 [--help] [--verbose] [--iwconfig-path=/sbin/iwconfig] [--ipconfig-path=/sbin/ifconfig] - [--dumpfile=result.txt] -Where: ---interface : Specify the wireless interface to use ---help : This help ---verbose : Verbose output to STDOUT ---ifconfig-path : Path to your ifconfig binary ---iwconfig-path : Path to your iwconfig binary ---tshark-path : Path to your tshark binary ---dumpfile : Save found SSID's/MAC addresses in a flat file (SIGUSR1) -_HELP_ - exit 0; -} - -# We must be run by root -(getlogin() ne "root") && die "$0 must be run by root!\n"; - -# We must have an interface to listen to -(!$interface) && die "No wireless interface speficied!\n"; - -# Check ifconfig availability -( ! -x $ifconfigPath) && die "ifconfig tool not found!\n"; - -# Check iwconfig availability -( ! -x $iwconfigPath) && die "iwconfig tool not found!\n"; - -# Check tshark availability -( ! -x $tsharkPath) && die "tshark tool not available!\n"; - -# Configure wireless interface -(system("$ifconfigPath $interface up")) && "Cannot initialize interface $interface!\n"; - -# Set interface in monitor mode -(system("$iwconfigPath $interface mode monitor")) && die "Cannot set interface $interface in monitoring mode!\n"; - -# Create the child process to change wireless channels -(!defined($pid = fork)) && die "Cannot fork child process!\n"; - -if ($pid) { - # --------------------------------- - # Parent process: run the main loop - # --------------------------------- - ($verbose) && print "!! Running with PID: $$ (child: $pid)\n"; - open(TSHARK, "$tsharkPath -i $interface -n -l subtype probereq |") || die "Cannot spawn tshark process!\n"; - while () { - chomp; - my $line = $_; - chomp($line = $_); - # Everything exept backslash (some probes contains the ssid in ascii, not usable) - #if($line = m/\d+\.\d+ ([a-zA-Z0-9:]+).+SSID=([a-zA-ZÀ-ÿ0-9"\s\!\@\$\%\^\&\*\(\)\_\-\+\=\[\]\{\}\,\.\?\>\<]+)/) { - if($line = m/\d+\.\d+ ([a-zA-Z0-9:_]+).+SSID=([a-zA-ZÀ-ÿ0-9"\s\!\@\$\%\^\&\*\(\)\_\-\+\=\[\]\{\}\,\.\?\>\<]+)/) { - if($2 ne "Broadcast") { # Ignore broadcasts - my $macAddress = $1; - my $newKey = $2; - print DEBUG "$macAddress : $newKey\n"; - if (! $detectedSSID{$newKey}) - { - # New network found! - my @newSSID = ( $newKey, # SSID - 1, # First packet - $macAddress, # MAC Address - time()); # Seen now - $detectedSSID{$newKey} = [ @newSSID ]; - $uniqueSSID++; - print "++ New probe request from $macAddress with SSID: $newKey [$uniqueSSID]\n"; - } - else - { - # Existing SSID found! - $detectedSSID{$newKey}[1]++; # Increase packets counter - $detectedSSID{$newKey}[2] = $macAddress; # MAC Address - $detectedSSID{$newKey}[3] = time(); # Now - ($verbose) && print "-- Probe seen before: $newKey [$uniqueSSID]\n"; - } - } - } - } -} -else { - # -------------------------------------------------- - # Child process: Switch channels at regular interval - # -------------------------------------------------- - ($verbose) && print STDOUT "!! Switching wireless channel every 5\".\n"; - while (1) { - for (my $channel = 1; $channel <= 12; $channel++) { - (system("$iwconfigPath $interface channel $channel")) && - die "Cannot set interface channel.\n"; - sleep(5); - } - } - -} - -sub dumpNetworks { - my $i; - my $key; - print STDOUT "!! Dumping detected networks:\n"; - print STDOUT "!! MAC Address SSID Count Last Seen\n"; - print STDOUT "!! -------------------- ------------------------------ ---------- -------------------\n"; - if ($dumpFile) { - open(DUMP, ">$dumpFile") || die "Cannot write to $dumpFile (Error: $?)"; - print DUMP "MAC Address SSID Count Last Seen\n"; - print DUMP "-------------------- ------------------------------ ---------- -------------------\n"; - } - for $key ( keys %detectedSSID) - { - my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($detectedSSID{$key}[2]); - my $lastSeen = sprintf("%04d/%02d/%02d %02d:%02d:%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec); - print STDOUT sprintf("!! %-20s %-30s %10s %-20s\n", $detectedSSID{$key}[2], - $detectedSSID{$key}[0], $detectedSSID{$key}[1], $lastSeen); - ($dumpFile) && print DUMP sprintf("%-20s %-30s %10s %-20s\n", - $detectedSSID{$key}[2], $detectedSSID{$key}[0], - $detectedSSID{$key}[1], $lastSeen); - } - print STDOUT "!! Total unique SSID: $uniqueSSID\n"; - ($dumpFile) && print DUMP "Total unique SSID: $uniqueSSID\n"; - close(DUMP); - return; -} - -sub cleanKill { - if ($pid) { - # Parent process: display information - print "!! Received kill signal!\n"; - kill 1, $pid; - dumpNetworks; - } - exit 0; -} diff --git a/README.md b/README.md new file mode 100644 index 0000000..bf2ff80 --- /dev/null +++ b/README.md @@ -0,0 +1,43 @@ +# hoover.pl - Wi-Fi probe requests sniffer + +Original idea by David Nelissen (twitter.com/davidnelissen) +Thank to him for allowing me to reuse the idea! + +This script scans for wireless probe requests and prints them out. +Hereby you can see for which SSID's devices nearby are searching. + +Copyright (c) 2012 David Nelissen & Xavier Mertens +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of copyright holders nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +## History + +* 2012/01/11 Created +* 2014/03/10 Merged OSX fork and made minor fixes (timestamp) + * Original source from https://github.com/xme/hoover + * OSX support from https://github.com/hermanbanken/hoover +* 2014/03/18 finished python version (same functionality as perl version) + diff --git a/hoover.pl b/hoover.pl index aa37134..7ffa1c0 100755 --- a/hoover.pl +++ b/hoover.pl @@ -50,14 +50,16 @@ my $uniqueSSID = 0; #uniq ssid counter my %detectedSSID; # Detected network will be stored in a hash table - # SSID, Seen packets, Last timestamp + # SSID, Seen packets, MAC, Last timestamp my $pid; my $help; my $verbose; my $interface; my $dumpFile; +my $osname = $^O; my $ifconfigPath = "/sbin/ifconfig"; my $iwconfigPath = "/sbin/iwconfig"; +my $airportPath = "/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport"; my $tsharkPath = "/usr/local/bin/tshark"; my $options = GetOptions( "verbose" => \$verbose, @@ -65,13 +67,13 @@ "interface=s" => \$interface, "ifconfig-path=s" => \$ifconfigPath, "iwconfig-path=s" => \$iwconfigPath, - "tsharkPath=s" => \$tsharkPath, + "tshark-path=s" => \$tsharkPath, "dumpfile=s" => \$dumpFile, ); if ($help) { print <<_HELP_; -Usage: $0 --interface=wlan0 [--help] [--verbose] [--iwconfig-path=/sbin/iwconfig] [--ipconfig-path=/sbin/ifconfig] +Usage: $0 --interface=en1_or_wlan0 [--help] [--verbose] [--iwconfig-path=/sbin/iwconfig] [--ipconfig-path=/sbin/ifconfig] [--dumpfile=result.txt] Where: --interface : Specify the wireless interface to use @@ -86,7 +88,7 @@ } # We must be run by root -(getlogin() ne "root") && die "$0 must be run by root!\n"; +($< != 0) && die "$0 must be run by root!\n"; # We must have an interface to listen to (!$interface) && die "No wireless interface speficied!\n"; @@ -95,7 +97,7 @@ ( ! -x $ifconfigPath) && die "ifconfig tool not found!\n"; # Check iwconfig availability -( ! -x $iwconfigPath) && die "iwconfig tool not found!\n"; +($osname ne 'darwin') && ( ! -x $iwconfigPath) && die "iwconfig tool not found!\n"; # Check tshark availability ( ! -x $tsharkPath) && die "tshark tool not available!\n"; @@ -104,7 +106,8 @@ (system("$ifconfigPath $interface up")) && "Cannot initialize interface $interface!\n"; # Set interface in monitor mode -(system("$iwconfigPath $interface mode monitor")) && die "Cannot set interface $interface in monitoring mode!\n"; +($osname ne 'darwin') && (system("$iwconfigPath $interface mode monitor")) && die "Cannot set interface $interface in monitoring mode!\n"; +($osname eq 'darwin') && (system("$airportPath $interface -z")) && die "Cannot disassociate interface $interface!\n"; # Create the child process to change wireless channels (!defined($pid = fork)) && die "Cannot fork child process!\n"; @@ -114,54 +117,72 @@ # Parent process: run the main loop # --------------------------------- ($verbose) && print "!! Running with PID: $$ (child: $pid)\n"; - open(TSHARK, "$tsharkPath -i $interface -n -l subtype probereq |") || die "Cannot spawn tshark process!\n"; + + # only valid packets and non-empty SSIDs: + my $displayFilter = "wlan.fcs_good==1 and not wlan_mgt.ssid==\\\"\\\""; + my $fieldParams = "-T fields -e wlan.sa -e wlan_mgt.ssid -Eseparator=,"; + my $tsharkCommandLine = "$tsharkPath -i $interface -n -l $fieldParams"; + if ($osname ne 'darwin') { + $tsharkCommandLine .= " subtype probereq -2 -R \"$displayFilter\" |"; + } else { + $tsharkCommandLine .= " -y PPI -2 -R \"wlan.fc.type_subtype==4 and $displayFilter\" |" + } + ($verbose) && print "!! command: $tsharkCommandLine\n"; + + open(TSHARK, $tsharkCommandLine) || die "Cannot spawn tshark process!\n"; while () { chomp; my $line = $_; chomp($line = $_); - # Everything exept backslash (some probes contains the ssid in ascii, not usable) - #if($line = m/\d+\.\d+ ([a-zA-Z0-9:]+).+SSID=([a-zA-ZÀ-ÿ0-9"\s\!\@\$\%\^\&\*\(\)\_\-\+\=\[\]\{\}\,\.\?\>\<]+)/) { - if($line = m/\d+\.\d+ ([a-zA-Z0-9:_]+).+SSID=([a-zA-ZÀ-ÿ0-9"\s\!\@\$\%\^\&\*\(\)\_\-\+\=\[\]\{\}\,\.\?\>\<]+)/) { - if($2 ne "Broadcast") { # Ignore broadcasts - my $macAddress = $1; - my $newKey = $2; - print DEBUG "$macAddress : $newKey\n"; - if (! $detectedSSID{$newKey}) - { - # New network found! - my @newSSID = ( $newKey, # SSID - 1, # First packet - $macAddress, # MAC Address - time()); # Seen now - $detectedSSID{$newKey} = [ @newSSID ]; - $uniqueSSID++; - print "++ New probe request from $macAddress with SSID: $newKey [$uniqueSSID]\n"; - } - else - { - # Existing SSID found! - $detectedSSID{$newKey}[1]++; # Increase packets counter - $detectedSSID{$newKey}[2] = $macAddress; # MAC Address - $detectedSSID{$newKey}[3] = time(); # Now - ($verbose) && print "-- Probe seen before: $newKey [$uniqueSSID]\n"; - } - } - } + my ($macAddress, $ssid) = split(/,/, $line); + ($verbose) && print "!! found packet: mac=$macAddress, ssid=$ssid\n"; + my $hashKey = "$macAddress-$ssid"; + if (! $detectedSSID{$hashKey}) + { + # New network found! + my @newSSID = ( $ssid, # SSID + 1, # First packet + $macAddress, # MAC Address + time()); # Seen now + $detectedSSID{$hashKey} = [ @newSSID ]; + $uniqueSSID++; + print "++ New probe request from $macAddress with SSID: $ssid [$uniqueSSID]\n"; + } + else + { + # Existing SSID found! + $detectedSSID{$hashKey}[1]++; # Increase packets counter + $detectedSSID{$hashKey}[2] = $macAddress; # MAC Address + $detectedSSID{$hashKey}[3] = time(); # Now + ($verbose) && print "-- Probe seen before: $hashKey [$uniqueSSID]\n"; + } } } else { # -------------------------------------------------- # Child process: Switch channels at regular interval # -------------------------------------------------- - ($verbose) && print STDOUT "!! Switching wireless channel every 5\".\n"; - while (1) { - for (my $channel = 1; $channel <= 12; $channel++) { - (system("$iwconfigPath $interface channel $channel")) && - die "Cannot set interface channel.\n"; - sleep(5); - } - } - + ($verbose) && print STDOUT "!! Switching wireless channel every 5 seconds.\n"; + if ($osname ne 'darwin') { + while (1) { + for (my $channel = 1; $channel <= 12; $channel++) { + ($verbose) && print STDOUT "!! Switching to channel $channel\n"; + (system("$iwconfigPath $interface channel $channel")) && + die "Cannot set interface channel.\n"; + sleep(5); + } + } + } + else { + while (1) { + for (my $channel = 1; $channel <= 14; $channel++) { + ($verbose) && print STDOUT "!! Switching to channel $channel\n"; + (system("$airportPath $interface -c$channel")) && + die "Cannot set interface channel.\n"; + sleep(5); + } + } + } } sub dumpNetworks { @@ -177,7 +198,7 @@ sub dumpNetworks { } for $key ( keys %detectedSSID) { - my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($detectedSSID{$key}[2]); + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($detectedSSID{$key}[3]); my $lastSeen = sprintf("%04d/%02d/%02d %02d:%02d:%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec); print STDOUT sprintf("!! %-20s %-30s %10s %-20s\n", $detectedSSID{$key}[2], $detectedSSID{$key}[0], $detectedSSID{$key}[1], $lastSeen); diff --git a/hoover.py b/hoover.py new file mode 100755 index 0000000..cf7ea44 --- /dev/null +++ b/hoover.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python + +import threading +import signal +import sys +import time +import subprocess +import os +import os.path +import argparse + + + +def signal_handler(signal, frame): + print 'You pressend CTRL+C, data is flushed into database/file...' + switchThread.running = False + switchThread.join() + formatString = "{0: <18} {1: <20} {2: <18}" + print formatString.format("mac", "ssid", "last seen") + for key, value in entries.iteritems(): + print formatString.format(value.mac, value.ssid, time.strftime("%Y%m%d-%H:%M:%S", value.timeLastSeen)) + sys.exit(0) + + +class switchChannelThread (threading.Thread): + def __init__(self, threadID, name, delayInSeconds): + threading.Thread.__init__(self) + self.threadID = threadID + self.name = name + if osname != "Darwin": + self.maxChannel = 12 + else: + self.maxChannel = 14 + self.delayInSeconds = delayInSeconds + self.running = True + def run(self): + print 'Starting switch channel thread using a dely of %d seconds' % self.delayInSeconds + while self.running: + for channel in range (1, self.maxChannel + 1): + if verbose: + print 'Switching to channel %d' % (channel) + if osname != "Darwin": + if subprocess.call([iwconfigPath, interface, "channel", str(channel)]) != 0: + self.running = False + sys.exit(4) + else: + if subprocess.call([airportPath, interface, "-c%d" % channel]) != 0: + self.running = False + sys.exit(4) + + time.sleep(self.delayInSeconds) + if not self.running: + return + +class Entry (object): + def __init__(self, mac, ssid, time): + self.mac = mac + self.ssid = ssid + self.timeLastSeen = time + + +osname = os.uname()[0] +if osname != "Darwin": + defaultInterface = "wlan0" +else: + defaultInterface = "en1" + +# command line parsing: +parser = argparse.ArgumentParser(description='Show and collect wlan request probes') +parser.add_argument('--interface', default=defaultInterface, + help='the interface used for monitoring') +parser.add_argument('--tsharkPath', default='/usr/local/bin/tshark', + help='path to tshark binary') +parser.add_argument('--ifconfigPath', default='/sbin/ifconfig', + help='path to ifconfig') +parser.add_argument('--iwconfigPath', default='/sbin/iwconfig', + help='path to iwconfig') +parser.add_argument('--verbose', action='store_true', help='verbose information') +args = parser.parse_args() + +tsharkPath = args.tsharkPath +ifconfigPath = args.ifconfigPath +iwconfigPath = args.iwconfigPath +interface = args.interface +verbose = args.verbose + +# only on osx: +airportPath = "/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport"; + +# check all params +if not os.path.isfile(tsharkPath): + print "tshark not found at path {0}".format(tsharkPath) + sys.exit(1) +if not os.path.isfile(ifconfigPath): + print "ifconfig not found at path {0}".format(ifconfigPath) + sys.exit(1) +if osname != "Darwin": + if not os.path.isfile(iwconfigPath): + print "iwconfig not found at path {0}".format(iwconfigPath) + sys.exit(1) + +# start interface +if subprocess.call([ifconfigPath, interface, 'up']) != 0: + print "cannot start interface: {0}".format(interface) + sys.exit(2) + +# Set interface in monitor mode +retVal = 0 +if osname != 'Darwin': + retVal = subprocess.call([iwconfigPath, interface, "mode", "monitor"]) +else: + retVal = subprocess.call([airportPath, interface, "-z"]) + +if retVal != 0: + print "cannot set interface to monitor mode: {0}".format(interface) + sys.exit(3) + +# start thread that switches channels +switchThread = switchChannelThread(1, 'SwitchChannel', 5) +switchThread.start() +signal.signal(signal.SIGINT, signal_handler) +print 'press CTRL+C to exit' +# signal.pause() + +# start tshark and read the results +displayFilter = "wlan.fcs_good==1 and not wlan_mgt.ssid==\\\"\\\""; +fieldParams = "-T fields -e wlan.sa -e wlan_mgt.ssid -Eseparator=,"; +tsharkCommandLine = "{0} -i {1} -n -l {2}" + +if (osname != 'Darwin'): + tsharkCommandLine += " subtype probereq -2 -R \"{3}\"" +else: + tsharkCommandLine += " -y PPI -2 -R \"wlan.fc.type_subtype==4 and {3}\"" + +tsharkCommandLine = tsharkCommandLine.format(tsharkPath, interface, fieldParams, displayFilter) + +if verbose: + print 'tshark command: %s\n' % tsharkCommandLine, + +DEVNULL = open(os.devnull, 'w') +popen = subprocess.Popen(tsharkCommandLine, shell=True, stdout=subprocess.PIPE, stderr=DEVNULL) + +# collect all Entry objects in entries +entries = {} + +for line in iter(popen.stdout.readline, ''): + line = line.rstrip() +# if verbose: +# print 'line: "%s"' % (line,) + if line.find(',') > 0: + mac, ssid = line.split(',', 1) + if line in entries: + if verbose: + print "entry found (seen before): mac: '{0}', ssid: '{1}'".format(mac,ssid) + entry = entries[line] + entry.timeLastSeen = time.localtime() + else: + print "new entry found: mac: '{0}', ssid: '{1}'".format(mac,ssid) + entries[line] = Entry(mac, ssid, time.localtime())