From ba4f134ea4686469573c72c0099448ed7d50b579 Mon Sep 17 00:00:00 2001 From: Sergey Ivanov <seriv@cs.umd.edu> Date: Wed, 23 May 2012 12:29:48 -0400 Subject: [PATCH] support for HOSTS {ALLOW|DENY} lists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hosts allow-deny lists are the coma or blank separated lists of a dotted decimal IPv4 addresses of the form a.b.c.d. to match incoming machine’s IP address exactly, or an 'ipaddr/n' where ipaddr is the IP address and n is the number of one bits in the netmask. The first to occur match gives the result, skipping other rules. If nothing matches IP is allowed. --- lib/Resmon/Config.pm | 24 ++++++++++++++++++++++++ lib/Resmon/Status.pm | 21 +++++++++++++++++++++ resmon | 2 +- resmon.conf.sample | 9 +++++++++ 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/lib/Resmon/Config.pm b/lib/Resmon/Config.pm index 7416038..0731d92 100755 --- a/lib/Resmon/Config.pm +++ b/lib/Resmon/Config.pm @@ -5,6 +5,22 @@ use warnings; use Sys::Hostname; + +sub split_ip_list { +# this code is taken from Marcel Gruenauer's <marcel@cpan.org> CPAN module Net::IP::Match + my $string = shift; + my $allow = shift; + my (@result,$quad,$bits,$matchbits,$int,$mask); + for (split (/\s*[,\s]\s*/, $string)) { + ($quad, $bits) = m!^(\d+\.\d+\.\d+\.\d+)(?:/(\d+))?!g; + $bits = 32 if ($bits eq ''); + $matchbits = 32 - $bits; + $int = unpack("N", pack("C4", split(/\./,$quad))); + $mask = $int >> $matchbits; + push @result => {mask => $mask, bits => $matchbits, allow => $allow}; + } + return \@result; +} sub new { my $class = shift; my $filename = shift; @@ -130,6 +146,14 @@ sub new { elsif(/\s*AUTHPASS\s+(\S+)\s*;\s*/) { $self->{authpass} = $1; next; + } + elsif(/\s*HOSTS\s+ALLOW\s+([^;]+)\s*;\s*/) { + push (@{$self->{hostsallow}}, @{split_ip_list($1,1)}); + next; + } + elsif(/\s*HOSTS\s+DENY\s+([^;]+)\s*;\s*/) { + push (@{$self->{hostsallow}}, @{split_ip_list($1,0)}); + next; } elsif(/\s*INCLUDE\s+(\S+)\s*;\s*/) { my $incglob = $1; diff --git a/lib/Resmon/Status.pm b/lib/Resmon/Status.pm index 7755c8f..19b6c20 100644 --- a/lib/Resmon/Status.pm +++ b/lib/Resmon/Status.pm @@ -441,6 +441,8 @@ sub serve_http_on { my $port = shift; $self->{authuser} = shift; $self->{authpass} = shift; + my $hostsallow = shift; + if(!defined($ip) || $ip eq '' || $ip eq '*') { $ip = INADDR_ANY; } else { @@ -469,6 +471,25 @@ sub serve_http_on { while(1) { my $client = $handle->accept; next unless $client; + my $hersockaddr = getpeername($client); + my ($port, $iaddr) = sockaddr_in($hersockaddr); + my $denied; + for my $el (@{$hostsallow}) { + my $tmp = unpack("N",$iaddr); + $tmp = $tmp >> $el->{bits} if $el->{bits}; + if ($tmp == $el->{mask}) { + $denied = !$el->{allow}; + last; + } + } + if ($denied) { + my $response = "<html><head><title>IP denied</title></head>" . + "<body><h1>IP denied</h1></body></html>"; + $client->print(http_header(401, length($response), 'text/html', $denied)); + $client->print($response . "\r\n"); + $client->close(); + next + }; my $req; my $proto; my $close_connection; diff --git a/resmon b/resmon index f3fd6fc..fd78b85 100755 --- a/resmon +++ b/resmon @@ -84,7 +84,7 @@ my $list = []; $status = Resmon::Status->new($config->{statusfile}); $status->open(); $status->serve_http_on($config->{interface}, $config->{port}, - $config->{authuser}, $config->{authpass}) + $config->{authuser}, $config->{authpass}, $config->{hostsallow}) if($config->{port}); while(1) { diff --git a/resmon.conf.sample b/resmon.conf.sample index f36b848..1319671 100755 --- a/resmon.conf.sample +++ b/resmon.conf.sample @@ -3,6 +3,15 @@ PORT 81; STATUSFILE /var/run/resmon-status.txt; TIMEOUT 10; +HOSTS ALLOW 10.80.116.112, 127.0.0.1; +# HOSTS {ALLOW/DENY} lists are the coma or blank separated lists of +# a dotted decimal IPv4 addresses of the form a.b.c.d. to match incoming machine’s IP address exactly, +# or an 'ipaddr/n' where ipaddr is the IP address and n is the number of one bits in the netmask. +# the first match gives the result, if nothing matches IP is allowed. +HOSTS DENY 10.80.117.128/25 +HOSTS ALLOW 10.80.116.0/23 +HOSTS DENY 0.0.0.0/0; + # Resmon health check. Shows the hostname, svn revision and # any problems with modules or the configuration file. Core::Resmon { -- GitLab