Tuesday, December 22, 2009

Reading the output of system commands in C

The system command in the standard C library lets you issue a commandline command and receive a return code. But that's not usually what you want. Let's say I wanted to issue a ps command to tell me which processes I was running, then how would I know the result? Actually there is a way, because the output of the command goes to stdout, and it is possible to redirect the output to a real file. For example:

FILE *console = freopen( "console", "w+", stdout );
redirects all standard output to a file called "console". After issuing the command:
ps aux | awk '/firefox/ && !/awk/ {print $4}'
console will contain the percentage of memory used by the 'firefox' process, if it was initiated by me. Then to read the result all you need to do is say:
rewind( console );
res = fscanf( console, "%f", &percent );
fclose( console );
and the float 'percent' will contain the percentage of the memory being used by Firefox. Not very efficient perhaps, but timing it reveals on my system that it only takes 10 milliseconds to execute, which is quick enough. And the information is precious - I can't find it out any other way (that's relatively platform-independent), and it tells me how much memory is being consumed by that particular process whose PID I don't even know.

So what's next?

So now I can get via SNMP the percent CPU usage and percent memory usage by a particular process every second. Next has to be the throughput or goodput of a particular port on a particular interface. This will be much harder and may be impossible.

Implementing the SET operation in a MIB

I wanted to set the name of the current application being monitored and then use snmpget on values that depend on that setting. I realise this is not quite the snmp way but it's just what I need to monitor a particular application's current state. That way I can retrieve for example the current application's memory and CPU usage as a percentage value. The snmp tutorial isn't very forthcoming about the details of how to do this. In particular it doesn't tell you where the commandline oid and value are located. All you get are four parameters:

  1. netsnmp_mib_handler *handler
  2. netsnmp_handler_registration *reginfo
  3. netsnmp_agent_request_info *reqinfo
  4. netsnmp_request_info *requests
Try searching the net-snmp site for information about these structures. I couldn't find anything. After some experimentation I managed to work out that the value of an snmpset command is stored in requests->requestvb->val.string and its length in requests->requestvb->val_len. The OID is stored in requests->requestvb->name (an array of ints) and its length in requests->requestvb->name_length (consistent huh?). I ignored most of the SET states (MODE_SET_RESERVE1, MODE_SET_RESERVE2, MODE_SET_FREE, MODE_SET_ACTION and MODE_SET_UNDO), and just provided code for MODE_SET_COMMIT. (The other states are for allocating and deallocating temporary memory). The storage for the string is just a global variable in the module. I just declared it as
static char currentAppName[APP_NAME_LEN];
where APP_NAME_LEN is 128. On receipt of a MODE_SET_COMMIT command I just copy the value at requests->requestvb->val.string into currentAppName. Of course I put a check in to stop more than 128 bytes being copied. I'm not that dumb.

What's next?

The next task is to compute currentAppCPUUsage and currentAppMemoryUsage based on the currentAppName value.

Sunday, December 20, 2009

Compiling your own SNMP subagent

I had some trouble remembering how to do this so I thought I would write down how to decipher the net-snmp tutorial instructions on how to build a subagent for your custom MIB.

Now why would you want a subagent? A subagent is just a demon that runs on its own and connects to the snmpd demon, so adding its functionality to the whole. The advantage of this approach is that you don't have to recompile the main agent or (almost as bad) compile it into a 'dynamically loadable object' which boils down to much the same thing as compiling it into the code. With a subagent you can bring your custom agent and its custom MIB up or down without disturbing the main agent.

Before you start you must have installed the libsnmp-dev package, which contains all the development headers. And also all the snmp and snmpd stuff as described in my earlier blog entry. But you knew that, right?

So, OK, how do you do it?

  1. First write a MIB. I used the NET-SNMP-TUTORIAL-MIB as a basis for my own. After examining it carefully for a few minutes changing it to do what I wanted was not hard. You have to change the names of the parts of the MIB tree to suit your variables.
  2. Next, turn the MIB into C. I used mib2c on the commandline:
    mib2c dosTFMIBObjects
    You are supposed to modify this but for a demo you can just leave it as is. You might want to modify the default values in the .c file though. 'dosTFMIBObjects' is the name of the main node of my custom MIB subtree. For this to work you must already have put your MIB file into .snmp/mibs.
  3. Modify the example-demon.c file (I renamed it dostf-demon.c) by changing the name of the init function to match your own.
  4. Now execute the manual compile steps, using the generated C file:
     gcc -I. `net-snmp-config --cflags` -c -o dostf-demon.o dostf-demon.c
     gcc -I. `net-snmp-config --cflags` -c -o dosTFMIB.o dosTFMIB.c
     gcc -o dostf-demon dostf-demon.o dosTFMIB.o `net-snmp-config --agent-libs`
    
  5. Finally, run your subagent:
    sudo ./dostf-demon
    And type in the password or it will fail to run correctly. You may also need to enable agentx. If so, add the line:
    master agentx
    to your /etc/snmp/snmpd.conf file and restart the snmpd service.

To access the values just use snmpget:

snmpget -v2c -c public localhost DOSTF-MIB::dosTFSubagentObject.0
This is the leaf-node of the MIB tree you created in your MIB. Now all you have to do is to modify the .c file you generated with mib2c so that it does something useful, i.e. actually computes the values you are retrieving.

Tuesday, December 8, 2009

Defining your own MIBs

Net-snmp has a flaw, at least on Linux. If you ask for anything from the IF-MIB at the rate of once a second, it chews up around 35% of the CPU processing power. This is not a good idea if what we want for the DDoS testbed is a discreet monitoring of each host. The cause is, according to this guy:

netsnmp_arch_interface_container_load() function from "if-mib/data_access/interface_linux.c" has a file pointer to "proc/net/dev" from it tries to get updates of each interface in a while loop, which takes too much of cpu time when we have many VLAN interfaces defined in our server this loads CPU 100%

So the way around it seems to be to write your own MIB. But how easy is that, exactly?

MIB files are defined using the arcane SMI syntax. But they can also be converted into C code, and then compiled. But you still need the textual MIB files to translate the even more arcance OIDs or dot-notation, into more meaningful textual identifiers. For example, in the Net-SNMP tutorial NET-SNMP-TUTORIAL-MIB::nstAgentModuleObject.0 represents the OID .1.3.6.1.4.1.8072.2.4.1.1.1.0. Another advantage of using the text-form of an OID is that snmpset then works with a simple "=" sign. Otherwise you have to tell snmpset the data type of the thing you are setting.

So far I have managed to compile the example SNMP mib C file at http://www.net-snmp.org/tutorial/tutorial-5/toolkit/mib_module/nstAgentModuleObject.c. What they suggest is to include this as part of your snmpd demon, so when you launch it, the demon will automatically recognise the numeric OID. If you want it also to recognise the text-form you have to add the text MIB to .snmp/mibs. Also I had to de-install net-snmp before I could get it to work, and also launch it with supervisor privileges. Simply putting the MIB files into .snmp/mibs is sufficient - the snmpd agent does not have to be restarted.

The next step is to rewrite the sample MIB to do something useful for the testbed. Also, to allow it to be added dynamically instead of requiring recompilation of the agent.

Tuesday, December 1, 2009

File Open and Save Buttons in HTML

HTML is designed for the big bad Internet, but if you use it as a format for interaction over a local network, as in our case, the security restrictions get rather annoying. The problem with the multipart form approach described below is that you don't have the path to the original file. I wanted to load a specific file, edit the contents and save it back – all in a HTML form. The loading worked – sort of – but the saving was impossible.

The Answer

What I did to get around the security restrictions was to define two applets, one an OPEN button, and the other a SAVE button. Each button creates a JFileChooser with appropriate settings. The code for this is trivial and is just a few lines of toy Java-SE. (I leave this as an exercise for the reader!) I pass in two parameters to the OPEN button applet: the name of the Javascript function I want to call to set a text field on the HTML page, and the id of that field. For the SAVE button I only pass in the name of the Javascript function to retrieve the file path from that field. This is called via LiveConnect, which is contained in the Netscape plugin.jar library that is included in every Java installation. Basically this technology allows you to call any Javascript function in the HTML page that the applet is embedded in. Using these simple tools I fashioned a pretty good lookalike <input type="file"/> field that actually works. One condition for this to work is that the two applets have to be in a signed jar along with the plugin.jar contents. Otherwise security prevents it from accessing the local file system. Just try to do this in standard HTML, after clicking on the 'SAVE' button: