Nagios is probably one of the most used network monitoring systems around. Especially in environments that have been around for a while and contain a lot of on-premises nodes.
I've recently started to upgrade an existing installation which included a lot of automation and updating from Nagios Core 3.x to Nagios Core 4.x. This resulted in an updated Web Interface with more PHP code and a more modern design.
One main gripe I have about the Nagios interface however is the use of Frames. The problem has not changed since the 3.x days:
- Nagios uses frames
- This means that the browser only ever shows the base url (https://example.com/nagios/) in the location bar
- When navigating to a specific service, e.g. /nagios/cgi-bin/extinfo.cgi?type=2, the location bar is unchanged and still points at the base URL.
- If I want to share a specific service status I need to copy the URL of the frame and send it to a colleague.
- Said colleague will only see the service status when opening that URL, no navigation bar will be shown, because that's in a different frame which we're bypassing.
This is a common issue with framesets and a complaint that basically came up 5 minutes after the introduction of frames in 1996.
Despite these complaints, frames can actually be very useful in many cases. When developing your own software, there are multiple options available to work around these frameset limitations. When using third-party software such as Nagios however, there's fewer options available.
For Nagios Core 3.x I had replaced the Nagios provided index.html page with my own index.php page that takes an optional parameter for the address of the main frame which allowed to construct URLs that open the regular Nagios interface with the navigation bar on the left frame and a e.g. specific service opened on the main frame to the right.
When porting this functionality I stumbled the fact that Nagios Core 4.x is already using PHP for some files and the default index.php already seems to have a parameter called "corewindow" that seems to offer this functionality. Unfortunately, there is barely any documentation around for this parameter. The first thing I found is a ChangeLog entry (https://www.nagios.org/projects/nagios-core/4x/) indicating this functionality is disabled by default due to a potential security vulnerability:
4.3.0 – 02/21/2017
Security
- Fix for CVE-2016-6209 – The “corewindow” parameter (as in http://localhost/nagios?corewindow=www.somewhere.com) has been disabled by default. See the UPGRADING document for how to enable it.
Well, Duh. If you take random URLs and use them to build a frameset defintion, this can indeed be "misused" to open a random URL inside your Frameset.
Personally, I wouldn't consider this a case of "works as designed" and not as a security issue but of course hapless users might be confused. Probably depends a lot on the users.
But this is exactly the functionality we need except it's disabled. The UPGRADING document states that one can re-enable the corewindow functionality using the --enable-corewindow Parameter when building Nagios.
But re-enabling said functionality is even easier. Just change line 4 in the index.php file from
if ("no"== "yes" && isset($_GET['corewindow'])) {
to
if ("yes"== "yes" && isset($_GET['corewindow'])) {
Done, that's the same thing the
--enable-corewindow parameter does.
On my system, that file is found at
/usr/share/nagios/html/index.php. Your system might be different.
If you now open /nagios/index.php?corewindow=nagios/tac.cgi the index file will open the Tactical Overview screen. Nice!
Functionality restored using the default installation. Perfect!
But can we improve things?
While looking for documentation for the corewindow parameter, I stumbled over Custom CGI Headers and Footers on the Nagios documentation. It seems the CGIs can load files and embed them in the HTML page...
This is brilliant. We can use some low key JavaScript logic to automatically update the browser location bar to add the corewindow parameter with the right link to the CGI.
This way, the location bar will always show a link to the specific view we're looking at right now and can be easily copy and pasted. No more right-click->frames->copy-frame-link dance.
This means we can create a file /usr/share/nagios/html/ssi/common-header.ssi drop some Javascript in there that handles the updates of the location bar and we're done. Awesome. The code needed is super simple:
<script>
/*
* Update the browser location bar to ensure ?corewindow= always contains the URI
* to the current page.
*
* This allows a reload to reload the same page rather than going back to the main
* frameset.
*/
// Get the current URL of the parent window (assuming the frame is nested within it)
var parentUrl = window.parent.location.href;
// Get the path of the file from the current URL of the frame
var filePath = window.location.pathname;
// Remove the first slash from the path name
filePath = filePath.substring(1);
// Get any query string parameters passed to the file
var queryString = window.location.search;
// Remove any existing corewindow parameter from the query string
queryString = queryString.replace(/(?:&|\?)corewindow=[^&]*&?/g, '');
// Construct the new query string with corewindow as the first parameter
var newQueryString = 'corewindow=' + filePath;
// Append any existing query string parameters
if (queryString) {
// Emcode only the '?' and the '&' component of the path.
newQueryString += encodeURIComponent('?') +
queryString.substring(1).split('&').join('%26');
}
// Construct the updated URL with the new query string
var updatedUrl = parentUrl.split('?')[0] + '?' + newQueryString;
// Replace the URL of the parent window with the updated URL
window.parent.history.replaceState(null, null, updatedUrl);
</script>
And done, now clicking inside the Nagios interface will update the location bar to URLs such as https://nagios.example.com/nagios/?corewindow=nagios/cgi-bin/extinfo.cgi%3Ftype=2%26host=filer-cluster%26service=fs_%2Fdev%2Fvg%2Barc_vol_000%2Flv%2Bn%2Blvarc_vol_00000 which is a link that opens the fs_/dev/vg+arc_vol_000/lv+n+lvarc_vol_00000 service on the filer-cluster host. Easy to share. Perfect.
Unfortunately, this solution is as close to perfect as we can build it using the shipped functionality, but it's not 100% perfect.
- This only works for .cgi files. The main.php file will not load the SSI file and thus it won't update the URL.
Not problematic in the grand scheme of things but a minor nitpic.
- Not all .cgis actuall load the SSI files. The map.cgi doesn't.
Also not super problematic because the map is not really used by us. But YMMV.
But overall, still a massive UX improvement.
Further reading:
Other people also have been using the SSI functionality to embed funky Javascript functionality. https://theezitguy.wordpress.com/2015/08/16/nagios-improve-user-experience-with-ssi-and-javascript/ is a good example.