automation, configuration, scripting, Uncategorized, wireless topics

Perl script for bulk update of radius server settings on Cisco WLCs

The task, which one may encounter, is to update radius authentication or accounting server settings on Cisco local wireless controllers (WLC) due to either IP of  radius authentication or accounting server is changed (e.g. old servers were scrapped, new ones deployed) or shared secret is changed or should be updated due to other reasons. Shown below script can do such tasks for Cisco WLCs as in my case such changes had to be done on ~60 local WLCs (with manual work such change would be quite stressful, prone to errors and took quite a lot of time).

Initial data and assumptions are:

1) per Cisco WLCs command line, there are no command options to reset shared secret for radius authentication or accounting server:

config radius acct

Pic.1 – Command line options of radius server on Cisco WLC command line

So if someone needs to update shared secret for radius authentication or accounting server, per Cisco’s design it is needed to delete related radius from WLC’s config and then to add it with new password (similar procedure if it is the case of changed IP of radius authentication or accounting server).

2) script below is using Net::SSH::Expect package. If someone uses Debian Linux or its derivatives, I would recommend to install such Perl package as .deb package (I will create separate topic about that), as CPAN or other ways of installation Perl modules sometimes hadn’t worked per my experience.

3) IP addresses of all WLCs, which should go through the change of radius authentication/accounting server, are stored in a separate text file (one IP per one line) which is passed as an argument to the script. For example, if presented script in your case is called “change_wlc_ALL_rad_acc_settings1_0_0.pl” then command to run the script will look following way (in such case file with WLCs IPs is “all_WLCs.txt” is located in the same folder with the script):

command line

Pic.2 – Example of running the provided script

4) script will automatically search defined by you SSIDs which are utilizing related radius authentication or accounting server. For this example script expects that such SSID names contain ABC, KLM, XYZ strings for identification them by regex.

5) “your_username” and “your_password” to authorise on WLCs should be replaced by yours

6) per Cisco’s design, to delete related radius authentication or accounting server it is firstly needed to disable all related SSIDs, which are using it, and delete related radius server from setting of such SSIDs. Script below expects that SSIDs “ABC”, “KLM” and  “XYZ” are using related radius server, so script will search these IDs of such SSIDs to remove related radius server from their settings.

7) script expects that radius accounting server in such example has IP 10.20.30.40 and will search it via regex to identify its ID for further changes with WLC’s  commands

8) script assumes that radius accounting ID on Cisco WLC should be 17 and it is using “acc_shared_secret” shared secret

9) to document all logging output (forchecking that all is executed as expected), tee command can be used, e.g.

@debian:~/scripts# ./change_wlc_ALL_rad_acc_settings1_0_0.pl all_WLCs.txt | tee /tmp/log_changes.log

this will save all output to /tmp/log_changes.log (and will show on console as well)

10) in script there are no correct mechanism to catch error due to unavailability of a certain WLC in a list, where it tries to establish SSH, or authentication problem to access SSH. In these two cases scrip will finish itself with error (such drawback to be improved)

Script itself is following :

#!/usr/bin/perl
#script to update radius acc servers on local WLCs


use Net::SSH::Expect;

my $filename = $ARGV[0];

if (open(my $fh, '<:encoding(UTF-8)', $filename)) {
while ( <$fh> ) {
chomp;
@fields = split(' ', $_);

my $ssh = Net::SSH::Expect->new (
host => $host1,
raw_pty => 1
);
print ("Getting into WLC $host1...n");
$ssh->run_ssh() or print "SSH process couldn't start: $!";
$ssh->waitfor('Are you sure you want to continue connecting (yes/no)?', 10) or print "n key already imported n";
$ssh->send("yesn");
$ssh->waitfor('User:', 20) or die "prompt 'User' not found after 20 second";
$ssh->send(" ");
$ssh->send("your_username");
$ssh->waitfor('Password:', 7) or print "prompt 'Password' not found after 7 second";
$ssh->send("your_password");
$ssh->waitfor('(Cisco Controller)', 7) or print "prompt 'Cisco Controller' not found";
print ($ssh->exec("config paging disable"));

#------search and identify WLAN ID of ABC------#
print ("Checking ABC WLAN id numbern");
$ssh_session =$ssh->exec("show wlan summary");
print ($$ssh_session);

#cutting line with related WLAN information:
($matching) = $ssh_session=~ /([^n]*ABC+)/is;
print ("n$matching");

my $ABC_wlan_id;
$matching =~ m/(d+)/g;
if ($matching ne "") {

$ABC_wlan_id=$1;
}
else {
$ABC_wlan_id=0;
}

print ("nn print ABC id= $ABC_wlan_id n");

#--search and identify WLAN ID of KLM--#

print ("Checking KLM WLAN id numbern");
$ssh_session =$ssh->exec("show wlan summary");
print ($$ssh_session);

#cutting line with related WLAN information:
($matching) = $ssh_session=~ /([^n]*KLM+)/is;
print ("n$matching");

my $KLM_wlan_id;
$matching =~ m/(d+)/g;
if ($matching ne "") {

$KLM_wlan_id=$1;
}
else {
$KLM_wlan_id=0;

}

print ("nn print KLM id= $KLM_wlan_id n");

#---search and identify WLAN ID of XYZ---#

print ("Checking XYZ WLAN id numbern");
#print ($ssh->exec("show wlan summary"));
$ssh_session =$ssh->exec("show wlan summary");
print ($$ssh_session);

#cutting line with related WLAN information:

($matching) = $ssh_session=~ /([^n]*XYZ+)/is;
print ("n$matching");

my $XYZ_wlan_id;
$matching =~ m/(d+)/g;
if ($matching ne "") {

#print ("n matching parameter= $matchingn");
$XYZ_wlan_id=$1;

}
else {
$XYZ_wlan_id=0;
}

print ("nn print XYZ id= $XYZ_wlan_id n");

#---------acc radius part----------#

$ssh_session =$ssh->exec("show radius summary");
print ($$ssh_session);
($matching) = $ssh_session=~ /([^n]*10.20.30.40+)/is;
print ("n$matching");
$matching =~ m/(d+)/g;
my $rad_id100;
if ($matching ne "") {
$rad_id100=$1;
}
else {
$rad_id100=0
}
print ("nn radius accounting id= $rad_id100 n");

#---apply related commands for changes---#
print("n disabling mentioned WLAN ABC");
print ($ssh->exec("config wlan disable $ABC_wlan_idn"));

print("n disabling mentioned WLAN KLM ");
print ($ssh->exec("config wlan disable $KLM _wlan_idn"));

print("n disabling mentioned WLAN XYZ ");
print ($ssh->exec("config wlan disable $XYZ _wlan_idn"));

print("n deleting acc radius server under ABC, SSID ID= $ABC_wlan_idn");
print ($ssh->exec("config wlan radius_server acct delete $ABC_wlan_id all"));
print("n deleting acc radius server under KLM, SSID ID= $KLM_wlan_idn");
print ($ssh->exec("config wlan radius_server acct delete $KLM_wlan_id all"));
print("n deleting acc radius server under XYZ, SSID ID= $XYZ_wlan_idn");
print ($ssh->exec("config wlan radius_server acct delete $XYZ_wlan_id all"));
print ("n radius acc ID is $rad_id100 n");
print("n deleting acc radius server under radius settings on WLC n");
print ($ssh->exec("config radius acc delete $rad_id100"));

# create radius acc server and enable WLANs

print("n adding acc radius server (with id=17) under radius settings on WLC n");
print ($ssh->exec("config radius acct add 17 10.20.30.40 1813 ascii acc_shared_secret"));
print ($ssh->exec("config radius acct network 17 enable"));
print ($ssh->exec("config radius acct disable 17"));
print ($ssh->exec("config radius acct retransmit-timeout 17 5"));
print ($ssh->exec("config radius acct enable 17"));

print("n adding acc radius server under ABC, SSID ID= $ABC_wlan_id n");
print ($ssh->exec("config wlan radius_server acct add $ABC_wlan_id 17"));
print ($ssh->exec("config wlan enable $ABC_wlan_id"));

print("n adding acc radius server under KLM, SSID ID= $KLM_wlan_id n");
print ($ssh->exec("config wlan radius_server acct add $KLM_wlan_id 17"));
print ($ssh->exec("config wlan enable $KLM_wlan_id"));

print("n adding acc radius server under XYZ, SSID ID= $XYZ_wlan_id n");
print ($ssh->exec("config wlan radius_server acct add $XYZ_wlan_id 17"));
print ($ssh->exec("config wlan enable $XYZ_wlan_id"));
print("n saving configuration file to flash memory n");
print ($ssh->exec("save config"));
print ($ssh->exec("y"));

}
} else {
warn "Could not open file '$filename' $!";
}

Uncategorized, wireless topics

Microwave motion detecting sensor and wifi

On the market there are such motion detecting sensors available, e.g.

http://simx.co.nz/product-groups/Standalone-Sensors/230vac/microsense-360-microwave-sensor1

https://www.aliexpress.com/item/32800683435.html

Per description, it “emits high-frequency electro-magnetic waves  with 5.8GHz and receives their echo. The sensor detects the change in echo from even the slightest
movement in the detection zone.”

If local wifi is working on 5Ghz band on UNII-3 channels (~5.7 – 5.8 GHz), such sensors will knock it down by making duty cycles equal to 100%

duty_cycle

 

monitoring, Uncategorized, wireless topics

monitor amount of users on Cisco access points

At this stage of wifi technology development high density of clients and access points can be seen quite often. Now is a task to avoid too much clients per access point (once I saw a report with ~90 clients on one access point) to offer reliable wifi service.

Amount of users per access points in certain moments of time can be gained via Cisco prime (PI – prime infrastructure, as it called by vendor). In my case this system is monitored by other persons and when they will restore its functionality is unclear. For such case or if someone don’t want to invest in Cisco prime, Bash script and SQL can be used to monitor amount of users per access points during the time:

1) login with Expect/Perl/Python script to WLC and monitor all output

2) issue command “show ap summary” and following result will be achieved (some columns are deleted for brevity):

(Cisco Controller) >show ap summary

Number of APs……………………………… 101

Global AP User Name………………………… mgmt
Global AP Dot1x User Name…………………… Not Configured

AP Name          AP Model                  Location           IP Address         Clients
——————    ——————–            —————-         —————        ——————–
235AP           AIR-CAP2702E-Z-K9    Stores               10.10.47.235          1
234AP           AIR-CAP2702E-Z-K9    Gnd F               10.10.47.234           1
233AP           AIR-CAP2702E-Z-K9    KP                     10.10.47.233           1
7213AP         AIR-CAP2702E-Z-K9    Aisle 4 – H5     10.105.82.26           0
7208AP         AIR-CAP2702E-Z-K9    Above Bench  10.105.82.33          3

3) this output can be saved in file, which afterwards can be used by a Bash and Perl scripts to push such data into MySQL on regular basis with help of cron on Linux.

4) the result looks good:

mysql> select dt,tm, sum(users_amount) from APs_users GROUP BY dt,tm;
+——————+————-+———————————+
|        dt            |        tm      | sum(users_amount) |
+——————+————-+————- ——————-+
| 2018-12-28  | 09:05:31 |              21                    |
| 2018-12-29  | 07:05:32 |              18                    |
| 2018-12-29  | 08:05:32 |              18                    |
+——————-+————+———————————+
3 rows in set (0.00 sec)

Uncategorized, wireless topics

Evaluate amount of user sessions from remote controllers on anchor

if someone has deployed Cisco guest anchor wireless controller, which by design can support up to 71 remote controllers, it is useful to evaluate from which remote controller how much user sessions come. To achieve this it is necessary to  get initial data from anchor controller via command “show client wlan 1” (lets assume you evaluating users on WLAN id #1):

(Cisco Controller) >show client wlan 1

Number of Clients in WLAN…………………… 1970

MAC Address                  AP Name             Status    Auth Protocol Port Wired Mobility Role Device Type
—————–                     —————–          ————-     —-    —————- —- —– —————————-

00:08:22:a6:87:34  10.10.1.12       Associated Yes Mobile 13   No Export Anchor Android
00:6d:52:01:60:41  10.1.20.25       Associated Yes Mobile 13 No Export Anchor Unclassified
00:6d:52:05:31:1c   10.11.17.10   Associated Yes Mobile 13 No Export Anchor Unclassified
00:6d:52:eb:48:08   10.20.96.22    Associated Yes Mobile 13 No Export Anchor Unclassified
00:ae:fa:52:59:e3    10.30.0.22       Associated Yes Mobile 13 No Export Anchor Unclassified
00:b3:62:10:80:69   10.44.0.24     Associated Yes Mobile 13 No Export Anchor Unclassified

If you have hundreds and thousands of such connections, it is more convenient to use   following command on the first step, which saves your time pressing all  the time confirmation button for the next page of data:

(Cisco Controller) >config paging disable

After data about user connections has been gathered in a file (e.g. /tmp/result.txt),  following command can be applied:

cat /tmp/result.txt | awk ‘{ print $2 }’ | sort | uniq -c | sort -rn

which will offer you following result:

840 10.22.30.11
652 10.1.20.25
546 10.46.40.20
517 10.34.55.78
489 10.45.100.11
488 10.16.200.233
etc.

This gives youa sorted list by amount of user connections (I would call it importance weight), which is a first column of the result, and IP address of respective remote wireless controller.

 

 

Uncategorized, wireless topics

limitation of Cisco wireless controllers per user sessions

for certain site and task Cisco wireless controller type is being chosen by max amount of supported of access points and max user connections. Here are some examples:

WLC 3504 supports (link):

  • 4-Gbps throughput
  • 150 access points
  • 3000 clients
  • 1x Multigigabit Ethernet interface (up to 5 Gigabit Ethernet), + 4x 1 Gigabit Ethernet
  • 4096 VLANs

WLC 5520 supports (link):

  • 20-Gbps throughput
  • 1500 access points
  • 20,000 clients
  • 4096 VLANs

Old type of wireless controller Cisco 5508 supports up to 7000 users. All users over the limit get no service per design from vendor. Here is what happens when there are more users would be connected to such WLC (hard limit on of the value 7000 on the graph):

number_of_stations.png