#!/usr/bin/perl -w use strict; system("PATH=\$PATH:/usr/sbin"); ############################################# ## ## ## Name: WLAN-Connect 0.4 ## ## Author: Mirza Muharemagic ## ## Email: mirza@php.co.ba ## ## WWW: http://www.php.co.ba/X31 ## ## License: BSD ## ## ## ## This script helps user to connect ## ## easier to a WLAN access point. It ## ## scans the area for APs, and gives the ## ## the user ability to connect to one of ## ## found APs pretty easy using nice GUI, ## ## instead of using command line tools. ## ## ## ## It requires: ## ## - Perl of course ## ## - Gnome Zenity for GUI ## ## - Wireless tools (iwconfig, iwlist) ## ## - lsmod, ifconfig, route, modprobe ## ## - Perl module Digest::MD5 (for WEP) ## ## ## ## Test Environment: ## ## - Slackware 9.1 ## ## - Intel PRO/Wireless 2100 (Centrino) ## ## ipw2100 ver. 0.5x ## ## ## ## WARNING: ## ## chmod this file to 700 to avoid abuse ## ## ## ############################################# my $APP = 'WLAN-Connect 0.4'; my (%WLAN,%WEP,$TEST); open STDERR, '>/dev/null'; ############################################## ## enter WLAN device and connection data here ############################################## ## Module name for WLAN device. If not set, it ## will not check whether the module is loaded ## Uncomment this option, if your driver is ## compiled in kernel. $WLAN{'module'} = 'ipw2100'; ## ipw2100 loads modules WEP modules automaticly. ## if your kernel is not configured to do this ## put 'modprobe module_name' here #modprobe hostap #modprobe hostap_crypt_wep ## Device name ## Possible values: eth0, eth1, wlan0 ... or 'auto' ## auto = script will try to find device automatically ## eth0, eth1, wlan0 ... = script will use given device $WLAN{'device'} = 'auto'; ## Enter here ESSIDs and Passwords ## Enter as many ESSIDs/Passwords as you want ## If chosen Access Point (ESSID) is not on this ## list and it requires password, you'll be ## asked to enter the password ## $WEP{'ESSID'} = 'PASSWORD' $WEP{'Mirza'} = '1234567890'; $WEP{'TestESSID'} = 'myPassword'; ## When to use power management for wireless? ## Possible values: off, battery, allways ## off = power management is allways OFF ## battery = power managament is ON only if running with battery ## allways = always use power management = allways ON $WLAN{'power_management_status'} = 'battery'; ## Which level of power management to use? ## Possible values: 1-5 ## 1-5 = Different levels of power management. ## The higher the number the greater the power ## savings, but with an impact to packet latencies. $WLAN{'power_management_level'} = '5'; ## if $TEST is set, only APs will be shown. You ## have no possibility to connect to an AP ## i just use it for testing the script #$TEST = 1; ############################################## ## Do not change anything below this line ## ## if you don't know what are you doing!!! ## ############################################## my (@Address,@ESSID,@Mode,@Frequency,@Encryption,@Quality,@Signal,@Noise); my ($iwconfig,$iwlist,$iwpriv,$lsmod,$modprobe,$ifconfig,$dhcpcd,$zenity); ## find zenity, iwconfig and other tools &NoTool("zenity") if !chomp($zenity = `which zenity`); &NoTool("iwconfig") if !chomp($iwconfig = `which iwconfig`); &NoTool("iwlist") if !chomp($iwlist = `which iwlist`); &NoTool("iwpriv") if !chomp($iwpriv = `which iwpriv`); &NoTool("lsmod") if !chomp($lsmod = `which lsmod`) && $WLAN{'module'}; &NoTool("modprobe") if !chomp($modprobe = `which modprobe`) && $WLAN{'module'}; &NoTool("ifconfig") if !chomp($ifconfig = `which ifconfig`); ## load kernel module &CheckWLANmodule; ## find wlan device if not set $WLAN{'device'} = &FindWLANdevice if ($WLAN{'device'} eq 'auto' || !$WLAN{'device'}); ## In Slackware, just run /etc/rc.d/rc.inet1. You can ## also use 'dhcpcd '. In other dists, you should ## probably use sth like: 'dhclient $WLAN{'device'}' ## I am using this, if an access point doesn't give an ## ip address to my WLAN device. usually, device should ## get the ip right after "modprobing" module or setting ## the right ESSID my $dhcpscript = "/sbin/dhcpcd -t 10 $WLAN{'device'}"; ############################################# ## Start the script ############################################# &PowerManagement; &FindAPs; ############################################# ## The functions ############################################# ## find wlan device (eth0 or eth1 etc) sub FindWLANdevice { my $WLANdevice; ## find device in proc open WLANDEV, '/proc/net/wireless'; while () { if ($_ =~/(eth|wlan)(\d)/) { $WLANdevice = $1.$2; last; } } close WLANDEV; ## if not found if (!$WLANdevice) { &Error("WLAN device not found. Please check your configuration.\nStopping $APP..."); } else { return $WLANdevice; } } ## check for module and load it if it isn't loaded sub CheckWLANmodule { return 1 if !exists($WLAN{'module'}) || $WLAN{'module'} eq ''; ## read lsmod to find module if (`$lsmod` !~/$WLAN{'module'}/g) { my $loaded = `$modprobe $WLAN{'module'}`; if (`$lsmod` !~/$WLAN{'module'}/g) { &Error("WLAN module '$WLAN{'module'}' could not be loaded.\nStopping $APP..."); } } } ## set power modes for WLAN device to save your battery. sub PowerManagement { my $power_state = `cat /proc/acpi/ac_adapter/AC/state`; ## power management ON if ($WLAN{'power_management_status'} eq 'allways' || ($WLAN{'power_management_status'} eq 'battery' && $power_state =~ /off\-line/)) { system("$iwpriv $WLAN{'device'} set_power $WLAN{'power_management_level'}"); ## power management OFF } else { system("$iwconfig $WLAN{'device'} power off"); } } ## unload WLANmodule if you don't need it sub UnloadWLANmodule { my $dialog_um = $zenity.' --question --title="Unload WLAN module" '. '--text="Do you want to unload WLAN-module \''.$WLAN{'module'}.'\'?"'; ## !!! this is zenity-BUG, it ## should be other way around if ($WLAN{'module'} && !system($dialog_um)) { my $unloaded = `$modprobe -r $WLAN{'module'}`; if (`$lsmod` =~/$WLAN{'module'}/g) { &Error("WLAN module '$WLAN{'module'}' could not be unloaded.\n". "Please unload it manually with\n'rmmod $WLAN{'module'}' ". "or 'modprobe -r $WLAN{'module'}'"); } } } ## it converts password to wep key ## copyright Aki Mimoto, see the link below ## http://mattfoster.clara.co.uk/madwifi-faq.htm sub MakeWepKey { require Digest::MD5; return (substr Digest::MD5::md5_hex( substr( shift() x 64, 0, 64 ) ), 0, 26); #print (substr Digest::MD5::md5_hex( substr( shift() x 64, 0, 64 ) ), 0, 26); } ## find access points sub FindAPs { my $apoints = `$iwlist $WLAN{'device'} scanning`; my @spoints = split /Cell/, $apoints; my $j=0; undef(@Address); undef(@ESSID); undef(@Mode); undef(@Frequency); undef(@Encryption); undef(@Quality); undef(@Signal); undef(@Noise); ## parse found APs for (my $i=0; $i<=$#spoints; $i++) { if ($spoints[$i] =~/Address:\s*(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)/i) { $j++; $Address[$j] = $1; if ($spoints[$i] =~/ESSID:\s*\"(\w+|)\"/i) { $ESSID[$j] = $1; } if ($spoints[$i] =~/Mode:\s*(Managed|Ad\-hoc|Auto|Master)\s*/i) { $Mode[$j] = $1; } if ($spoints[$i] =~/Frequency:\s*([\w\.]+)\s*/i) { $Frequency[$j] = $1; } if ($spoints[$i] =~/Encryption key:\s*(on|off)\s*/i) { $Encryption[$j] = $1; } if ($spoints[$i] =~/Quality:(.*?)\s/i) { $Quality[$j] = $1; } if ($spoints[$i] =~/Signal level:(.*?)\sdBm/i) { $Signal[$j] = $1; } if ($spoints[$i] =~/Noise level:(.*?)\s*dBm/i) { $Noise[$j] = $1; } } } ## show found APs &ListAPs; } ## list APs sub ListAPs { my $dialog_ap = $zenity.' --list --width=620 --height=250 '. '--title="'.$APP.': Choose an Access Point and click OK" '. '--column="No." '. '--column="ESSID " '. '--column="MAC " '. '--column=" Mode " '. '--column="Encr." '. '--column="Quality" '. '--column=" Signal " '. '--column=" Noise " '. '--separator="~" '; for (my $j=1; $j<=$#Address; $j++) { $dialog_ap .= '" '.$j.'. " '. '"'.$ESSID[$j].'" '. '"'.$Address[$j].'" '. '" '.$Mode[$j].'" '. '" '.$Encryption[$j].' " '. '" '.$Quality[$j].'" '. '" '.$Signal[$j].'dBm" '. '" '.$Noise[$j].'dBm" '; } ## show the dialog with access points and ## connect to a chosen Access Point if (my $aplist = `$dialog_ap`) { ## delete . and spaces $aplist =~s/\.//g; $aplist =~s/\s//g; ## call the AP-chooser &ConnectToAP($aplist); } else { &UnloadWLANmodule; } } ## enter password dialog sub EnterPassword() { my $dialog_password = $zenity.' --entry --title="'.$APP.': '. 'The Access Point requires a password:" '. '--text="This Access Point is using encrypted connection.\n\n'. 'Please enter the password:\n"'; chomp(my $password = `$dialog_password`); print $password; return $password; # if (length(my $password = `$dialog_password`) > 1) { # chomp($password); # return $password; # } else { # &EnterPassword; # } } ## connect to a chosen AP sub ConnectToAP() { my $APchoice = shift; ## remove pid file if it was left by dhcpcd my $rm_dhcpcdpid = `rm /etc/dhcpc/dhcpcd-$WLAN{'device'}.pid`; ## if the AP needs the password if ($Encryption[$APchoice] eq "on") { if (!exists($WEP{$ESSID[$APchoice]})) { system("$iwconfig $WLAN{'device'} key ".MakeWepKey(&EnterPassword)." open") if !$TEST; } else { system("$iwconfig $WLAN{'device'} key ".MakeWepKey($WEP{$ESSID[$APchoice]})." open") if !$TEST; } } if (!$TEST) { ## set Access Point MAC Address system("$iwconfig $WLAN{'device'} ap $Address[$APchoice]"); ## if the AP has no ESSID, set it to 'any' $ESSID[$APchoice] = $ESSID[$APchoice] ? $ESSID[$APchoice] : 'any'; ## set ESSID after setting key. setting ESSID before key is not possible system("$iwconfig $WLAN{'device'} essid $ESSID[$APchoice]"); ## get IP from Access Point using DHCP system("$dhcpscript"); } ## show new ifconfig data &ShowIfconfig; } sub ShowIfconfig { ## show ifconfig for this device to check whether IP is set my ($ip,$bcast,$mask,$essid,$apmac,$encryption,$security_mode,$power_management); my $ifconfigdata = `$ifconfig $WLAN{'device'}`; my $iwconfigdata = `$iwconfig $WLAN{'device'}`; ## parse ifconfig and iwconfig data if ($ifconfigdata =~/inet addr:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/gi) { $ip = $1; } else { $ip = ''; } if ($ifconfigdata =~/Bcast:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/gi) { $bcast = $1; } if ($ifconfigdata =~/Mask:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/gi) { $mask = $1; } if ($iwconfigdata =~/ESSID:\"(\w+)\"/gi) { $essid = $1; } if ($iwconfigdata =~/Access Point:\s+(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)/gi) { $apmac = $1; } if ($iwconfigdata =~/Encryption key:(.*?)\s/gi) { $encryption = $1; } if ($iwconfigdata =~/Security mode:(.*?)\s/gi) { $security_mode = $1; } if ($iwconfigdata =~/Power Management( period)?:(.*?)\s/gi) { $power_management = $2; } # my $dialog_ipinfo = $zenity.' --info --title="'.$APP.': New connection data" '. # '--width=450 --text="'. # 'IP Address: '.$ip.' \n'. # 'Broadcast: '.$bcast.'\n'. # 'Netmask: '.$mask.'\n\n'. # 'ESSID: '.$essid.'\n'. # 'AP-MAC: '.$apmac.'\n'; # if ($encryption ne 'off') { # $dialog_ipinfo .= 'Encryption Key: '.$encryption.'\n'. # 'Security mode: '.$security_mode.'\n'; # } else { # $dialog_ipinfo .= 'Encryption: off\n'; # } # $dialog_ipinfo .= 'Power Management: '.$power_management.'"'; ## this list window looks much better than info window my $dialog_ip = $zenity.' --list --radiolist --checklist --width=450 --height=250 '. '--title="'.$APP.': Click on Cancel to choose another AP" '. '--column="" '. '--column="Type" '. '--column="Value " '. '--separator="~" '; $dialog_ip .= 'TRUE "IP Address:" "'.$ip.'" '. 'FALSE "Broadcast:" "'.$bcast.'" '. 'FALSE "Netmask:" "'.$mask.'" '. 'FALSE "ESSID:" "'.$essid.'" '. 'FALSE "AP-MAC" "'.$apmac.'" '; if ($encryption ne 'off') { $dialog_ip .= 'FALSE "Encryption Key:" "'.$encryption.'" '. 'FALSE "Security mode:" "'.$security_mode.'" '; } else { $dialog_ip .= 'FALSE "Encryption:" "off" '; } $dialog_ip .= 'FALSE "Power Management:" "'.$power_management.'"'; ## connect to a chosen Access Point if (my $ifconfig_info = `$dialog_ip`) { exit(0); } else { &FindAPs; } } ## show error if some of the required tools were not found sub NoTool { my $tool = shift; my $error_title = '"'.$APP.': '.$tool.'" not found'; my $error = '"'.$tool.'" was not found. It is probably '. 'not in the \$PATH of this user or it is not installed. '. 'Maybe this user does not have the rights to use it. '. 'Please check this and start the '.$APP.' again.'; ## if the missing tool is zenity, show ## the error on the command line & die if ($tool eq 'zenity') { system("clear"); print "###########################\n". "## $APP\n". "###########################\n\n". "*** Error ***\n\n". "'zenity' is not available\n\n". "'zenity' is the Gnome tool for showing dialog boxes. It is required ". "by $APP. It is probably not in the \$PATH of this user. Please check ". "this and start the $APP again.\n\n"; exit(0); } else { &Error($error,$error_title); } } ## it shows error messages sub Error { my ($error,$error_title) = @_; my $_error = $zenity.' --error --title="'.(!$error_title ? $APP.': Error' : $error_title).'" '. '--text="'.$error.'"'; system($_error); exit(0); } ## if included 1;