#!/usr/bin/perl -w ############################################################ # # $Id: rrd-server.cgi 693 2006-06-26 19:11:42Z nicolaw $ # rrd-server.cgi - Data gathering CGI script for RRD::Simple # # Copyright 2006, 2007 Nicola Worthington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################ # vim:ts=4:sw=4:tw=78 # User defined constants use constant BASEDIR => '/home/nicolaw/webroot/www/rrd.me.uk'; ############################################################ use 5.6.1; use warnings; use strict; use Socket; # We'll need to print a header unless we're in MOD_PERL land print "Content-type: plain/text\n\n" unless exists $ENV{MOD_PERL}; my $host; my $param = get_query($ENV{QUERY_STRING}); my $remote_addr = $ENV{REMOTE_ADDR}; # Take the host from the "target" if they know the "secret" if (defined($ENV{RRD_SECRET}) && defined($param->{secret} && defined($param->{target})) && "$ENV{RRD_SECRET}" eq "$param->{secret}") { $host = $param->{target}; } else { # Check for HTTP proxy source addresses for (qw(HTTP_X_FORWARDED_FOR HTTP_VIA HTTP_CLIENT_IP HTTP_PROXY_CONNECTION FORWARDED_FOR X_FORWARDED_FOR X_HTTP_FORWARDED_FOR HTTP_FORWARDED)) { if (defined $ENV{$_} && $ENV{$_} =~ /([\d\.]+)/) { my $ip = $1; if (isIP($ip)) { $remote_addr = $ip; last; } } } # Fail if we can't see who is sending us this data unless ($remote_addr) { print "FAILED - NO REMOTE_ADDR\n"; exit; } $host = ip2host($remote_addr); my $ip = host2ip($host); # Fail if we don't believe they are who their DNS says they are if ("$ip" ne "$remote_addr") { print "FAILED - FORWARD AND REVERSE DNS DO NOT MATCH\n"; exit; } # Custom hostname flanges $host = 'legolas.wd.tfb.net' if $host eq 'bb-87-80-233-47.ukonline.co.uk' || $ip eq '87.80.233.47'; $host = 'pippin.wd.tfb.net' if $host eq '82.153.185.41' || $ip eq '82.153.185.41'; $host = 'pippin.wd.tfb.net' if $host eq '82.153.185.40' || $ip eq '82.153.185.40'; $host = 'isle-of-cats.etla.org' if $ip eq '82.71.23.88'; } # Build a list of valid pairs my @pairs; while (<>) { #warn "$host $_"; next unless /^\d+\.[\w\.\-\_\d]+\s+[\d\.]+\s*$/; push @pairs, $_; } # Don't bother opening a pipe if there's nothing to sent unless (@pairs) { printf("OKAY - %s - no valid pairs\n", $host); } else { # Simply open a handle to the rrd-server.pl and send in the data if (open(PH,'|-', BASEDIR."/bin/rrd-server.pl -u $host")) { print PH $_ for @pairs; close(PH); printf("OKAY - %s - received %d pairs\n", $host, scalar(@pairs)); # Say if we failed the customer :) } else { print "FAILED - UNABLE TO EXECUTE\n"; } } exit; sub get_query { my $str = shift; my $kv = {}; $str =~ tr/&;/&/s; $str =~ s/^[&;]+//, $str =~ s/[&;]+$//; for (split /[&;]/, $str) { my ($k,$v) = split(/=/, $_, 2); next if $k eq ''; $kv->{url_decode($k)} = url_decode($v); } return $kv; } sub url_decode { local $_ = @_ ? shift : $_; defined or return; tr/+/ /; s/%([a-fA-F0-9]{2})/pack "H2", $1/eg; return $_; } sub ip2host { my $ip = shift; my @numbers = split(/\./, $ip); my $ip_number = pack("C4", @numbers); my ($host) = (gethostbyaddr($ip_number, 2))[0]; if (defined $host && $host) { return $host; } else { return $ip; } } sub isIP { return 0 unless defined $_[0]; return 1 if $_[0] =~ /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\. (25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\. (25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\. (25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/x; return 0; } sub resolve { return ip2host(@_) if isIP($_[0]); return host2ip(@_); } sub host2ip { my $host = shift; my @addresses = gethostbyname($host); if (@addresses > 0) { @addresses = map { inet_ntoa($_) } @addresses[4 .. $#addresses]; return wantarray ? @addresses : $addresses[0]; } else { return $host; } } 1;