Cisco 911 Monitoring Without the $40K+ Price Tag

Actually I think the final price we were quoted was $20,000 on one product that did this, but initially we were told $40,000 (Hell, I think the product from Cisco was $60k)... Anyway, one of the things we were tasked with at work was setting up a system to monitor when 911 was called. When it was called we were to notify a set of individuals based on which office it was. It turns out this is incredibly simple. All we need to do is set up an SFTP server, set some info on the Cisco Call Manager, and parse the data with a couple lines of code.

The first step that we need to do is set up our SFTP server. If you search for SFTP, you'll notice a lot of references to SSH. SSH is a network protocol that allows for secure content exchange. Well, mostly secure anyway. Last vulnerability that I remember reading about was 2008 and I would have hoped that they would have fixed it by now. That being said, SFTP is simply an FTP server that uses SSH (yay, secure file transfers). Now all we have to do is set up SSH and we have an SFTP server. Now if we were a Linux shop at work, it would have been literally 5 minutes to set up the user login (SSH is already installed). On Windows, we have to install it ourselves. On the bright side this is fairly simple as there are 20+ versions out there. The one that I recommend is freeSSHd though as it's just incredibly simple (sadly we found it after setting up another SSH server at work). It's literally run the install app, follow directions, set up a user using their tray icon app, and you're done (note that on Windows Server 2008, there seems to be a bug where it saves your changes to the user's directory, which causes the service to not be able to find your changes. But you can simply do a search for the duplicate with the actual changes and simply copy it over the one in the app's directory. Just make sure to restart the service).

Once you have the SFTP server up and running, you simply go into the Cisco CallManager, go to Navigation->Cisco Unified CallManager Serviceability->click Go. The go to the Tools menu and select CDR Management. In the Billing Application Server Parameters section, click Add New. This is where you're tell it where your SFTP server is. So just enter the IP address of the server, username/password that you set up, directory that you want them to save to, and set the protocol to SFTP. Once that's done click save and you're done with the second step.

At this point you should have a folder on your SFTP server filling with files. These come in two flavors, files that start with cmr and those that start with cdr. The cmr files deal with call quality (packets sent, received, etc.). If you wanted, you could probably do some nice metrics of your system using that. The cdr files, on the other hand, actually give you information about who made the call, to whom, etc. If you open up one of these cdr files, you'll notice some info with a bunch of commas... It's a CSV file! Yay, parsing those is always fun... Thankfully I have some code that does that already. Although you may want the one from my utility library as I can't remember if the code there is updated or not (where as the utility library code is always up to date).

Anyway in the CSV we really only want a couple of fields. The first is the person calling (we can either use the extension, which is the 9th field, or the IP address if you have that nicely mapped out, which is the 80th field), the person being called (in this case we only care about 911 but we could monitor for anything really, but the field we want is the 30th), and maybe the time (which is the 48th field, and done as the number of seconds since 1/1/1970). So all of that being said, our code is going to look something like this:

    class Program

    {

        static void Main(string[] args)

        {

            try

            {

                EmailSender Sender = new EmailSender();

                Sender.To = "MyEmailAddress";

                Sender.From = "AGenericSystemEmailAddress";

                Sender.Server = "Your SMTP Server";

                Sender.Priority = MailPriority.High;

                Sender.Subject = "911 was called";

                Sender.Body = "";

 

                DateTime Start=new DateTime(1970,1,1);

                List<FileInfo> Files = Utilities.IO.FileManager.FileList("Directory of your call logs", true);

                foreach (FileInfo File in Files)

                {

                    bool Found = false;

                    string IPAddress = "";

                    string Extension="";

                    if (File.Name.ToLower().StartsWith("cdr"))

                    {

                        try

                        {

                            Utilities.FileFormats.CSV.CSV CSVFile = new Utilities.FileFormats.CSV.CSV(Utilities.IO.FileManager.GetFileContents(File.FullName));

                            for (int x = 2; x < CSVFile.NumberOfRows; ++x)

                            {

                                if (CSVFile[x][29].Value == "911" || CSVFile[x][29].Value == "8911")

                                {

                                    IPAddress = CSVFile[x][80].Value;

                                    Extension = CSVFile[x][8].Value;

                                    Found = true;

                                }

                                if (Found)

                                {

                                    DateTime TimeCalled = Start.AddSeconds(int.Parse(CSVFile[x][47].Value)).AddHours(-4);

                                    Sender.Body = "911 was called<br />";

                                    Sender.Body += "Time Called: " + TimeCalled.ToString() + "<br />";

                                    Sender.Body += "Extension: " + Extension + "<br />";

                                    Sender.Body += "IP Address: " + IPAddress + "<br />";

                                    Sender.SendMail();

                                    Found = false;

                                }

                            }

                        }

                        catch { }

                    }

                }

 

                for (int x = 0; x < Files.Count; ++x)

                {

                    try

                    {

                        Files[x].Delete();

                    }

                    catch { }

                }

            }

            catch { throw; }

        }

    }

Note that I'm using stuff from my utility library to make things shorter/simpler. Specifically the EmailSender is nothing but a wrapper for the built in .Net SMTP code, the FileManager is used to get the list of files in the directory and also an individual file's contents, and I'm using the CSV parser that I mentioned earlier (feel free to switch any of this stuff out for your own code). But that's it. With that bit of code (once you fill in the needed fields, etc.) you're good to go. Just set that up as a task to run on the server every minute or two and you have yourself a 911 notifier that only costs you a little bit of time. Plus going this route opens up a whole bunch of potential things that you could look for and do. So take a look, try it out, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 8/27/2010 at 8:17 AM
Tags: , ,
Categories: General
Post Information: Permalink | Comments (1) | Post RSSRSS comment feed

HaterAide ORM updated to 1.6

I've been quite for a while. The reason for this is two fold. First, I've been on vacation for a while with minimal access to the internet. The second reason is I've been working a lot on HaterAide ORM. For those that never read the series, HaterAide was a learning project for me. I wanted to see how difficult it was to create a basic ORM, what the "magic" was behind them, etc. I find that recreating the wheel is the best way for me to learn something and I've definitely learned a lot thus far from working on it. Since the initial postings and release it has added a number of features that put it up to the level of half way decent (we're even using it at my work now). This release added a number of features including:

1) Added transaction support
2) Added paging support
3) Added ability to override the default table and column names
4) Added ability to mark the database read only or write only
5) Added ability to do batch saving (calling Save when sending in a list of objects will save the entire list in one transaction).
6) Speed increases for all IEnumerables.
7) General speed increases for saving items.
8) Non int/GUID primary keys now work.
9) Size of DLLs reduced considerably.
10) Added the ability to save an object as a sub type.
11) Solution is now Visual Studio 2010
12) Separated database config data so that in the future multiple databases can be supported
13) Added switch so you can auto update the database or manually update the structure of the database.
14) DotCache, Aspectus, and Gestalt are integrated to make the system more modular.
15) Added better checks for null values/non existant objects in the database

Plus a number of fixes. I still need to add features like multiple databases, composite keys, etc. but it's coming along. So give it a look, try it out (usage documentation is included in this release), and happy coding.

Edit: It helps if I put a link to the new download...

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 8/17/2010 at 5:16 PM
Tags: , ,
Categories: General
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

UUID Doesn't Match Error When Using SVN

Just a quick update, for anyone who is using CodePlex for any sort of code repository (or you like getting the updates for my projects, etc), you'll notice a potential error that you'll get. You may end up getting something along the lines of "Repository UUID 'whatever' doesn't match expected UUID 'another GUID'. In order to fix this the people at CodePlex are saying to do a fresh checkout. That's all well and fine as long as you don't have 20 updates that need to go into the repository (which I did as I'm a bit lazy on the commits). An easier way (at least for me) was to find the "entries" file in the .svn directories and simply change the UUID from what they currently say to what svn wants. I did this simply using NotePad++, using "Replace In Files". Of course you need to make sure you set the files to writable first instead of Read Only but whatever. You can also go and take a look here for another approach.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 7/30/2010 at 4:53 PM
Tags: ,
Categories: General
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed