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' $!";
}

automation, configuration, network components, scripting, Uncategorized

script on expect language to push batch changes to cisco and aruba switches / routers

Notes about the script:

– in such particular case script pushes new syslog server 10.10.10.21 to configuration and saves config file
– script works almost without changes on cisco and aruba (on cisco though syntax is “logging host <…>” on aruba it is “logging <…>”)
– script will terminate itself with error if it will be not able to establish ssh to any of mentioned switches/routers where it needs to do changes
– logging from aruba is a mambo-jumbo and not accepted as a solution (the same result I get if doing logging via tee command of Expect script and with Expect’s logging possibility by log_file command (in my script its log_file -a $Directory/session_$host.log) )
– script expects that directory /tmp/logs exists, hence either it should be created manually or by adjusting provided script
– “log_file” command in script closes logging for each host, otherwise I got complaints from Expect related to not closed logging
– script reads IP addresses of each aruba / cisco switch or router from a file, which is given as a parameter to a script:

case for cisco
./set_syslog_on_cisco_v1.0.ex /tmp/cisco.txt | tee /tmp/cisco_syslog.log

case for aruba
./set_syslog_on_aruba_v1.0.ex /tmp/aruba.txt | tee /tmp/aruba_syslog.log

below is example of script for aruba case, for cisco case one line should be changed:

compare

 

#!/usr/bin/expect -f

set timeout 20

set file [lindex $argv 0];

set f [open “$file”]

set hosts [split [read $f] “n”]

close $f

foreach host $hosts {

if {$host != “”} {

send “echo host is $hostr”

sleep 2

set Username “your_username”

set Password “your_password”

set Directory /tmp/logs

log_file -a $Directory/session_$host.log

send_log “### /START-SSH-SESSION/ IP: $host @ [exec date] ###r”

spawn ssh -o “StrictHostKeyChecking no” $Username@$host

expect “*assword: ”

send “$Passwordr”

expect “#”

send “conf tr”

expect “(config)#”

send “logging 10.10.10.21r”

expect “(config)#”

send “endr”

expect “#”

send “wr memr”

expect “#”
send “r”

send “logoutr”

sleep 2

send_log “r### /END-SSH-SESSION/ IP: $host @ [exec date] ###r”

log_file;
}
}

configuration, Uncategorized, wireless topics

Peers configuration for guest wifi on Cisco wireless controllers

Infrastructure diagram for guest wifi service is well known:
guest wifi topology

            Pic.1 – Diagram for guest wifi service (diagram is taken from “design guide”)

Between local wireless controllers located on site (shown and named as “campus controllers” or “foreign WLCs”) and wireless controller located in DMZ (shown and named usually as “anchor controller”) should be configured and built EoIP tunnel. This article is dedicated to describe how correctly to configure this tunnel, as no documentation from cisco.com has such detailed information.

For functioning guest wifi service status of a tunnel should be UP (local WLC and anchor WLC show status of this tunnel as UP when all is correct):

peers status

Pic.2 – EoIP tunnel is established

To build a peer it is needed

1) IP address of management interface on remote peer (if you do configuration on anchor, its need IP of management interface on foreign WLC and vice versa – for foreign WLC its needed management IP of anchor WLC)

2) member MAC address: is tricky case as it is needed to use MAC address of virtual interface of the remote site. If any side (local WLCs or anchor WLC(s)) is in HA-SSO mode, then its needed to use high-availability virtual MAC address, which can be received by command (or from GUI via https access)

(Cisco Controller) >show redundancy summary

3) Group name – is Local Mobility Group of remote side and it is cAsE senSiTivE

peer parameters

Pic.3 – EoIP tunnel is established

If at least one of 1), 2) or 3) is not fulfilled peer will not be up and will show “data path is down” or “control path is down”.

4) firewall rules between anchor WLC (usually located in DMZ) and local WLCs should be cleared. From my experience such ports are needed:

“Legacy mobility: IP Protocol 97 for user data traffic, UDP Port 16666”

Despite it is called “legacy mobility” it is used by firmware 8.5.140.0, per firewall logs, UDP 16667 is not used, despite it is mentioned as

“New mobility: UDP Port 16666 and 16667”  under related Q&A

Additionally, per my memory, communication for EoIP is initiated from anchor (I’ve never seen such details on cisco documentations), but to be 100% sure, it is recommended to enable ACLs so that EoIP can be initiated from local WLCs as well as from anchor WLC, because for stateful firewall it is important which side initiates communication.

If mentioned in 4) details are not taken into account, then status of EoIP peer will be shown as “control and data path down“, “data path is down” or “control path is down”, depending on what is configured in related access lists.

 

P.S.: it is worse also to mention that Cisco suggests to have identical WLAN settings on local WLC and anchor, e.g. if “11k Neighbor List” is enabled on local WLC under guest wifi WLAN, then such setting should be enabled on anchor as well. The same is true for QoS settings under respective WLAN and other parameters.

 

 

configuration, scripting, Uncategorized, wireless topics

Script to batch change authentication server on Cisco wireless controllers

Task description:

-there are more than 100 Cisco wireless controllers in a region

– it old authentication radius servers 10.10.0.100 & 10.10.0.101 are approaching end-of-support and should be replaced by  new one 10.10.0.73.

– on each of wireless controller there are can be one or two wifi SSIDs which are using mentioned old radius servers. In this script they will be called “Office1” & “Office2”. Under their settings script will replace old radius servers by new one. Regex are being used to identify under which IDs “Office1” & “Office2” are configured on each particular WLC

– for SSH into each device Perl module Net::SSH::Expect is used

– script output can be logged by Linux tee command to verify that all done correctly

– script reads IP addresses of each WLC from a file, which is given as a parameter to a script:

./this_script.pl file_with_WLCs_IPs.txt | tee result.log

Script itself may be not perfect but done in a short time and describes an approach which can be optimized and made more advanced:


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

use Net::SSH::Expect;
my $filename = $ARGV[0];

my $username=”your_username”;
my $password=”your_password”;
if (open(my $fh, ‘<:encoding(UTF-8)’, $filename)) {
while ( <$fh> ) {
chomp;
@fields = split(‘ ‘, $_);

$host1 = $fields[0];
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(“$username”);
$ssh->waitfor(‘Password:’, 7) or print “prompt ‘Password’ not found after 7 second”;
$ssh->send(“$password”);
$ssh->waitfor(‘(Cisco Controller)’, 7) or print “prompt ‘Cisco Controller’ not found”;
print ($ssh->exec(“config paging disable”));

print (“Checking ‘Office1’ WLAN id numbern”);
$ssh_session =$ssh->exec(“show wlan summary”);
print ($$ssh_session);

#cutting line with office WLAN information:
($matching) = $ssh_session=~ /([^n]*Office1+)/is;
print (“n$matching”);

my $wlan_id1;
$matching =~ m/(d+)/g;
if ($matching ne “”) {

$wlan_id1=$1;
}
else {
$wlan_id1=0;
}
$ssh_session =$ssh->exec(“show wlan summary”);
print ($$ssh_session);
#cutting line with Office2 WLAN information
($matching) = $ssh_session=~ /([^n]*Office2+)/is;
print (“n$matching”);
$matching =~ m/(d+)/g;

my $wlan_id2;
if ($matching ne “”) {
$wlan_id2=$1;

}
else {
$wlan_id2=0;
}

print (“nn print Office1 wifi id= $wlan_id1, Office2 id=$wlan_id2 n”);
$ssh_session =$ssh->exec(“show radius summary”);
print ($$ssh_session);
($matching) = $ssh_session=~ /([^n]*10.10.0.100+)/is;
print (“n$matching”);
$matching =~ m/(d+)/g;
my $rad_id100;
if ($matching ne “”) {
$rad_id100=$1;
}
else {
$rad_id100=0
}
$ssh_session =$ssh->exec(“show radius summary”);
print ($$ssh_session);
($matching) = $ssh_session=~ /([^n]*10.10.0.101+)/is;
print (“n$matching”);
$matching =~ m/(d+)/g;
my $rad_id101;
if ($matching ne “”) {
$rad_id101=$1;
}
else {
$rad_id101=0;
}
$ssh_session =$ssh->exec(“show radius summary”);
print ($$ssh_session);
($matching) = $ssh_session=~ /([^n]*10.10.0.73+)/is;
print (“n$matching”);
$matching =~ m/(d+)/g;

my $rad_id73;
if ($matching ne “”) {
$rad_id73=$1;
}
else {
$rad_id73=0;
}
print (“n rad_id100 = $rad_id100, rad_id101 = $rad_id101, rad_id73 = $rad_id73 “);

print(“n disabling mentioned WLANs “);
print ($ssh->exec(“config wlan disable $wlan_id1”));
print ($ssh->exec(“config wlan disable $wlan_id2”));
print(“n deleting all auth radius servers under related WLANs “);
print ($ssh->exec(“config wlan radius_server auth delete $wlan_id1 all”));
print ($ssh->exec(“config wlan radius_server auth delete $wlan_id2 all”));

print(“n deleting all auth radius servers under radius settings on WLC “);
print ($ssh->exec(“config radius auth delete $rad_id100”));
print ($ssh->exec(“config radius auth delete $rad_id101”));
print ($ssh->exec(“config radius auth delete $rad_id73”));

# to check the case that auth radius servers have been configured with id equal to 1, otherwise throw warning in log and configure new radius with id=30
if (($rad_id100==1) || ($rad_id101==1) || ($rad_id73==1)) {
print(“n adding new auth radius server (with id=1) under radius settings on WLC n”);
print ($ssh->exec(“config radius auth add 1 10.10.0.73 1812 ascii inf2_acs_key”));
print ($ssh->exec(“config radius auth disable 1”));
print ($ssh->exec(“config radius auth rfc3576 enable 1”));
print ($ssh->exec(“config radius auth retransmit-timeout 1 5”));
print ($ssh->exec(“config radius auth management 1 disable”));
print ($ssh->exec(“config radius auth network 1 enable”));
print ($ssh->exec(“config radius auth enable 1”));
print ($ssh->exec(“config wlan radius_server auth add $wlan_id1 1”));
print ($ssh->exec(“config wlan radius_server auth add $wlan_id2 1”));
print ($ssh->exec(“config wlan enable $wlan_id1”));
print ($ssh->exec(“config wlan enable $wlan_id2”));

}

else {
#my $min_rad_id = min ($rad_id100, $rad_id101, $rad_id73);
print(“n ADDING NEW RADIUS SERVER (WITH ID=30) UNDER RADIUS SETTINGS ON WLC n”);
print ($ssh->exec(“config radius auth add 30 10.10.0.73 1812 ascii inf2_acs_key”));
print ($ssh->exec(“config radius auth disable 30”));
print ($ssh->exec(“config radius auth rfc3576 enable 30”));
print ($ssh->exec(“config radius auth retransmit-timeout 30 5”));
print ($ssh->exec(“config radius auth management 30 disable”));
print ($ssh->exec(“config radius auth network 30 enable”));
print ($ssh->exec(“config radius auth enable 30”));
print ($ssh->exec(“config wlan radius_server auth add $wlan_id1 30”));
print ($ssh->exec(“config wlan radius_server auth add $wlan_id2 30”));
print ($ssh->exec(“config wlan enable $wlan_id1”));
print ($ssh->exec(“config wlan enable $wlan_id2”));
}

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’ $!”;
}

 

configuration, network components, Uncategorized

Linux for console connection to network devices

USB-RS232_

I’ve noticed that my old USB-to-RS232 converter is not recognized by windows10 (no related driver and COM port does not appear when converter is plugged). On vendor’s site  no more support starting from windows8.

However modern Linux supports this converter without any effort. Here are steps how with help of computer with Linux install Linux on USB memory stick and use USB-to-RS232 converter with help of such Linux:

1) download fresh ISO version of Linux distro, e.g. I’ve done it with LinuxMint

2)   plug USB memory stick, identify which /dev/sd it is associated (with help of /var/log/syslog or lshw utility)

sudo umount /dev/sd  
sudo dd bs=4M if= of=/dev/sd conv=fdatasync

In my particular example USB has been identified as /dev/sdb and I used following dd command (without bs size parameter, which is used to speed up the process):

sudo dd of=Downloads/linuxmint-19.1-xfce-64bit.iso of=/dev/sdb

this takes ~10-15 minutes, command will show nothing till it finish copy data to USB stick. After that, live system on USB memory stick is ready.

3)  computer, which will be used for console connection, should be booted up into system, which has been installed in USB memory stick. By default LinuxMint does not have old good console program “minicom”,  hence it is required to connect to the internet and issue command

sudo apt install minicom

4) after minicom has been installed, it is needed to plug USB-to-RS232 converter, identify type device file /dev/ttyUSB  for it:

sudo dmesg | grep tty

in my system it was /dev/ttyUSB0:

tty-usb-converter.png

5)  final step: run minicom, instruct it which /dev/ttyUSB is associated to USB-to-RS232 converter and set speed to 9600 instead of default value 115200 shown below on the picture. Afterwards network device can be configured via this converter (you will see console responses of the network device if all done correctly):

sudo minicom -s

minicom parameters

Network device is asking for authentication and ready for configuration:

minicom configure network device