Real World IT: Backing Up Cisco Routers using .NET

Usually, in a company, there is a “development” department and a “IT” department, and usually the departments don’t really work together. Development is focused on delivering business value through coding applications for end users or B2B clients. IT is busy making sure the corporate network is humming along, and that other internal issues related to technology in general are taken care of.

In my experience, I like to jump the threshold between the two departments. I started out working Helpdesk (IT Dept) and coded in the time I had free, eventually starting/breaking into the Development side. But, my passion for internal IT functions didn’t slow. Some of the guys I worked with in the IT Department always wanted applications to do specific things for OUR network, things you can’t buy, or things that you can buy a generic application for way to much money and it won’t work exactly how you want it to. That is where developers and IT can actually work together and bridge that gap.

This post is about backing up configurations on Cisco routers using .NET (C#). Now, most developers programming away on business applications really don’t care about the routers inside their company. They know they are there, might know somewhat how they work, and as long as they work, its fine – that is what IT is all about. But on the other hand, the Network Administrator really cares about Cisco routers. He dreams about them. Names his kid Cisco, or Switch.

Now, the network admin can login to all his routers, and run some commands to backup his configs. The most usual way to do this is to send the config to a TFTP server. Now, if they want a backup once a month, and they have one router, well then great, a manual solution is fine. The network is probably not big or complex and the network admin needs something to do. In most cases though, they would want to back up their routers daily, and they might have multiple routers.

In this scenario, let the network admin set up the TFTP server. Those are abundant and easy to find, easy to setup. What we are concerned with from a development standpoint is actually logging into the router, running commands to backup the config (to the TFTP server) and getting out.

Now, a few things are needed from your network admin. First, you are going to need the IP addresses of all the routers. Next, you want to make sure that they have one user on all the routers with the same password that you can use just for this backup program. There are multiple ways I am sure they can do this, and since I am not a network guru, leave that to them – they will throw out terms like RADIUS, etc, but it should be easy for them. Next, you need them to make sure that all routers are set up the same, as far as the way they use “enable” commands, etc.

The first thing you want to do is take that information from your network admin, and then test each one manually. Telnet (or SSH if you can get that working) using the IP, login with the user and password, and then run the enable command, and look at the strings that are responsed back to you. Every router has a name like

company-router-123>

where the > is the prompt. You need to jot down this name to go along with the IP address. Now you can get fancy later and have your network admin set that name up in DNS and then you can just have a list of names, but start with IP addresses first.

Now, here comes the developing part. A long long time ago, right when .NET hit the airwaves, I created a class library called Winsock.Telnet so I could use it. Named it Winsock because I was a VB6 developer and I used the Winsock control to do telnets within my programs, so it just made sense. I still use this library today, and I do have the source code to it somewhere buried on a backup DVD or server in my apartment, and finding it would just be a wasted effort at this point, but the class library works, so that is what matters. I use this class library to do my telnets. (To do SSH I have used WeOnlyDo’s .net SSH Client – Chris Super blogs about how to run SSH on your network yet still use telnet for a specific purpose – such as this). You can get my Winsock library here.

Here is the guts of the main method to log a config from a Cisco router. Steps are easy. Connect, login, enable, run the TFTP command, send in the TFTP address, and a path , then exit. The second half is extra credit. I actually set up a SVN repo to the directory on the server that I TFTP the configs to, do a SVN diff, and if different, I email the changes to the network admin. But everything up the “exit” command would get you buy. The Sleep(1) function just waits for a second, which with telnet you need to do, so you don’t overrun your self. I have included the methods to do the SVN diff.

 

        private static void LogRouterConfigTelnet(string deviceName, string ipAddress, string enablePassword)
        {
            _connectorTelnet = new WinsockTelnet.Winsock(ipAddress, 23, 60);
            _connectorTelnet.Connect();
            _connectorTelnet.WaitAndSend("Username:", _username);
            _connectorTelnet.WaitAndSend("Password:", _password);
            _connectorTelnet.WaitAndSend(deviceName + ">", "enable");
            _connectorTelnet.WaitAndSend("Password:", enablePassword);

            Sleep(1);

            _connectorTelnet.SendAndWait("copy run tftp", "[]?");
            _connectorTelnet.SendAndWait(_tftpAddress, "?");
            _connectorTelnet.SendAndWait("routers/" + deviceName + "/" + _filename, deviceName + "#");
            _connectorTelnet.SendMessage("exit");
            _connectorTelnet.Disconnect();

            // copy over svn copies, delete from root folder
            File.Copy(@"C:TFTP-Rootrouters" + deviceName + @"" + _filename, @"c:tftp-sourcerouters" + deviceName + ".txt", true);

            // do svn diff
            string diff = SVNDiff(deviceName + ".txt");

            if (!string.IsNullOrEmpty(diff))
            {
                System.Console.WriteLine(diff);

                // if different, commit to svn, email diffs
                SVNCommit(deviceName + ".txt");

                EmailDiff(deviceName, diff.Replace(Environment.NewLine, "<br>").Replace("n", "<br>"));
            }


        }

        private static string SVNDiff(string filename)
        {
            ProcessStartInfo psi = new ProcessStartInfo();
            psi.FileName = @"C:Program FilesSubversionbinsvn.exe";
            psi.WorkingDirectory = @"C:tftp-sourceRouters";

            psi.Arguments = String.Format("diff {0}", filename);

            psi.UseShellExecute = false;
            psi.RedirectStandardOutput = true;
            psi.CreateNoWindow = true;

            Process p;
            String output;

            p = Process.Start(psi);

            try
            {
                output = p.StandardOutput.ReadToEnd();
                p.WaitForExit();

            }
            finally
            {
                // shouldnt happen but lets play it safe
                if (!p.HasExited)
                {
                    p.Kill();
                }
            }

            return output.Trim();

        }

        private static void SVNCommit(string filename)
        {
            ProcessStartInfo psi = new ProcessStartInfo();
            psi.FileName = @"C:Program FilesSubversionbinsvn.exe";
            psi.WorkingDirectory = @"C:tftp-sourceRouters";

            psi.Arguments = String.Format("commit -m "config changed" {0}", filename);

            psi.UseShellExecute = false;
            psi.RedirectStandardOutput = true;
            psi.CreateNoWindow = true;

            Process p;
            String output;

            p = Process.Start(psi);

            try
            {
                output = p.StandardOutput.ReadToEnd();
                p.WaitForExit();

            }
            finally
            {
                // shouldnt happen but lets play it safe
                if (!p.HasExited)
                {
                    p.Kill();
                }
            }

        }

        static void EmailDiff(string deviceName, string diff)
        {

            MailMessage msg = new MailMessage();
            msg.To = "networkadmin@yourcompany.com";

            msg.From = "ciscoconfig@yourcompany.com";
            msg.Subject = "Cisco Config Changed - " + deviceName;
            msg.Body = diff;
            msg.BodyFormat = MailFormat.Html;
            SmtpMail.SmtpServer = "yourmailserver";

            try
            {
                SmtpMail.Send(msg);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.ToString());
            }

        }

        static void Sleep(int seconds)
        {
            System.Threading.Thread.Sleep(seconds * 1000);
        }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }


 So, you can see, taking a little time to create a small program to do this is not really tough. And your IT department will be happy. It will also give you a reason to use things in .NET that you might not use everyday, especially if you are a Web Programmer, and also you will learn a little more about IT things (routers, networks, etc).

Note: you can see the code isn’t the prettiest, and really doesn’t need to be. There is some duplication yeah, and some hardcoded paths. If you are worried, release a 2.0 version with all that in the App.Config and refactor out a couple of methods. Or if you get really good, create a library called Utils or something with all the common functions you are going to use, like for calling processes, etc.

 

Advertisements

2 thoughts on “Real World IT: Backing Up Cisco Routers using .NET”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s