1package Mail::SpamAssassin::Spamd::Apache2::AclIP;
2use strict;
3use Apache2::Connection ();
4use Apache2::Const -compile => qw(OK FORBIDDEN SERVER_ERROR);
5
6use Apache2::Module    ();
7use Apache2::ServerRec ();
8
9use Apache::Test;
10use constant APACHE24   => have_min_apache_version('2.4.0');
11
12use Mail::SpamAssassin::Logger;
13
14=head1 NAME
15
16Mail::SpamAssassin::Spamd::Apache2::AclIP - host-based spamd access control
17
18=head1 SYNOPSIS
19
20 ##### in httpd.conf:
21 PerlLoadModule Mail::SpamAssassin::Spamd::Apache2::Config
22 SAallow from 127.0.0.1 192.168.0.0/24
23
24=head1 DESCRIPTION
25
26Allows / denies access to spamd basing on client's network address.
27This is a simple version of C<mod_authz_host> (which, unfortunately,
28is too HTTP-centric to use here).
29
30Should be before C<Mail::SpamAssassin::Spamd::Apache2::AclRFC1413>
31in the handler chain.
32
33=head1 NOTE
34
35This module doesn't prevent Apache from accepting a connection; child
36(and therefore we) get control after client actually sends something.
37It's possible to open C<$toomany> connections to the parent server and
38DoS this way.
39
40=head1 BUGS
41
42See <http://bugzilla.spamassassin.org/>
43
44=head1 SEE ALSO
45
46C<Mail::SpamAssassin::Spamd::Apache2::Config(3)>
47
48=cut
49
50use APR::IpSubnet ();
51
52sub handler {
53  my ($c) = @_;
54
55  my $srv_cfg =
56    Apache2::Module::get_config('Mail::SpamAssassin::Spamd::Apache2::Config',
57    $c->base_server);
58
59  # TODO: log it somewhere (or not?) -- means all denied
60  return Apache2::Const::SERVER_ERROR
61    unless $srv_cfg && exists $srv_cfg->{allowed_ips};
62
63  # use NetAddr::IP::Lite ();
64  # my $ip = NetAddr::IP::Lite->new($c->remote_ip)
65  #   or return Apache2::Const::SERVER_ERROR;   # log it, shouldn't happen
66
67  #use Apache::Test have_min_apache_version to support MP under Apache 2.2 and 2.4
68  my $remote = APACHE24 ? $c->client_addr : $c->remote_addr;
69
70  for my $allowed (@{ $srv_cfg->{allowed_networks} }) {
71    # depends on allowed_ips format; TODO; if NetAddr::IP::Lite:
72    # return Apache2::Const::OK if $allowed->contains($ip);
73    return Apache2::Const::OK if $allowed->test($remote);
74  }
75
76  info(sprintf "access denied for '%s'", APACHE24 ? $c->client_ip : $c->remote_ip);
77
78  return Apache2::Const::FORBIDDEN;
79}
80
811;
82
83# vim: ts=8 sw=2 et
84