You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spamassassin.apache.org by he...@apache.org on 2018/10/15 17:33:59 UTC

svn commit: r1843928 - in /spamassassin/trunk/lib/Mail: SpamAssassin.pm SpamAssassin/GeoDB.pm SpamAssassin/Plugin/RelayCountry.pm SpamAssassin/Plugin/URILocalBL.pm

Author: hege
Date: Mon Oct 15 17:33:59 2018
New Revision: 1843928

URL: http://svn.apache.org/viewvc?rev=1843928&view=rev
Log:
Use single shared GeoDB instance for plugins

Modified:
    spamassassin/trunk/lib/Mail/SpamAssassin.pm
    spamassassin/trunk/lib/Mail/SpamAssassin/GeoDB.pm
    spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/RelayCountry.pm
    spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/URILocalBL.pm

Modified: spamassassin/trunk/lib/Mail/SpamAssassin.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin.pm?rev=1843928&r1=1843927&r2=1843928&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin.pm Mon Oct 15 17:33:59 2018
@@ -1801,6 +1801,21 @@ sub init {
   # should be called only after configuration has been parsed
   $self->{resolver} = Mail::SpamAssassin::DnsResolver->new($self);
 
+  # load GeoDB if some plugin wants it
+  if ($self->{geodb_wanted}) {
+    eval '
+      use Mail::SpamAssassin::GeoDB;
+      $self->{geodb} = Mail::SpamAssassin::GeoDB->new({
+        conf => $self->{conf}->{geodb},
+        wanted => $self->{geodb_wanted},
+      });
+      1;
+    ';
+    if ($@ || !$self->{geodb}) {
+      dbg("config: GeoDB disabled: $@");
+    }
+  }
+
   # TODO -- open DNS cache etc. if necessary
 }
 

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/GeoDB.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/GeoDB.pm?rev=1843928&r1=1843927&r2=1843928&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/GeoDB.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/GeoDB.pm Mon Oct 15 17:33:59 2018
@@ -19,6 +19,15 @@
 
 Mail::SpamAssassin::GeoDB - unified interface for geoip modules
 
+Plugins need to signal SA main package the modules they want loaded
+
+package Mail::SpamAssassin::Plugin::MyPlugin;
+sub new {
+  ...
+  $self->{main}->{geodb_wanted}->{country} = 1;
+  $self->{main}->{geodb_wanted}->{isp} = 1;
+)
+
 (internal stuff still subject to change)
 
 =cut
@@ -126,478 +135,511 @@ sub new {
 sub init_database {
   my ($self, $opts) = @_;
 
-  my $geodb_module = $opts->{conf}->{module} || undef;
-  my $geodb_dbs = $opts->{conf}->{options} || {};
-  my $geodb_wanted = $opts->{wanted} || {};
-
-  my @geoip_search_path = defined $opts->{conf}->{geodb_search_path} ?
-    @{$opts->{conf}->{geodb_search_path}} : @geoip_default_path;
+  # Try city too if country wanted
+  $opts->{wanted}->{city} = 1 if $opts->{wanted}->{country};
+  # Try isp too if asn wanted
+  $opts->{wanted}->{isp} = 1 if $opts->{wanted}->{asn};
+
+  my $geodb_opts = {
+    'module' => $opts->{conf}->{module} || undef,
+    'dbs' => $opts->{conf}->{options} || undef,
+    'wanted' => $opts->{wanted} || undef,
+    'search_path' => defined $opts->{conf}->{geodb_search_path} ?
+      $opts->{conf}->{geodb_search_path} : \@geoip_default_path,
+  };
 
-  my $db;
-  my $dbapi;
+  my ($db, $dbapi);
 
-  ##
   ## GeoIP2
-  ##
+  if (!$db && (!$geodb_opts->{module} || $geodb_opts->{module} eq 'geoip2')) {
+    ($db, $dbapi) = $self->load_geoip2($geodb_opts);
+  }
 
-  if (!$db && (!$geodb_module || $geodb_module eq 'geoip2')) {
-    my $prep_ok = 0;
-    eval {
-      require GeoIP2::Database::Reader;
-      $prep_ok = 1;
-    } or do {
-      dbg("geodb: GeoIP2::Database::Reader module load failed: $@");
-    };
+  ## Geo::IP
+  if (!$db && (!$geodb_opts->{module} || $geodb_opts->{module} eq 'geoip')) {
+    ($db, $dbapi) = $self->load_geoip($geodb_opts);
+  }
 
-    if ($prep_ok) {
-      my %path;
-      foreach my $dbtype (@geoip_types) {
-        # only autosearch if no absolute path given
-        next if %$geodb_dbs && !exists $geodb_dbs->{$dbtype};
-        # skip if not needed
-        next if %$geodb_wanted && !$geodb_wanted->{$dbtype};
-        # skip country if city already loaded
-        next if $dbtype eq 'country' && $db->{city};
-        # skip asn if isp already loaded
-        next if $dbtype eq 'asn' && $db->{isp};
-        if (!defined $geodb_dbs->{$dbtype}) {
-          # Try some default locations
-          PATHS_GEOIP2: foreach my $p (@geoip_search_path) {
-            foreach my $f (@{$geoip2_default_files{$dbtype}}) {
-              if (-f "$p/$f") {
-                $path{$dbtype} = "$p/$f";
-                dbg("geodb: GeoIP2: search found $dbtype $p/$f");
-                last PATHS_GEOIP2;
-              }
-            }
-          }
-        } else {
-          if (!-f $geodb_dbs->{$dbtype}) {
-            dbg("geodb: GeoIP2: $dbtype database requested, but not found: ".$geodb_dbs->{$dbtype});
-            next;
-          }
-          $path{$dbtype} = $geodb_dbs->{$dbtype};
-        }
+  ## IP::Country::DB_File
+  if (!$db && $geodb_opts->{module} && $geodb_opts->{module} eq 'dbfile') {
+    # Only try if geodb_module and path to ipcc.db specified
+    ($db, $dbapi) = $self->load_dbfile($geodb_opts);
+  }
 
-        if (defined $path{$dbtype}) {
-          eval {
-            $db->{$dbtype} = GeoIP2::Database::Reader->new(
-              file => $path{$dbtype},
-              locales => [ 'en' ]
-            );
-            die "unknown error" unless $db->{$dbtype};
-            1;
-          } or do {
-            $@ =~ s/\s+Trace begun.*//s;
-            dbg("geodb: GeoIP2: $dbtype load failed: $@");
-          };
-        } else {
-          my $from = defined $geodb_dbs->{$dbtype} ?
-            $geodb_dbs->{$dbtype} : "default locations";
-          dbg("geodb: GeoIP2: $dbtype database not found from $from");
-        } 
+  ## IP::Country::Fast
+  if (!$db && (!$geodb_opts->{module} || $geodb_opts->{module} eq 'fast')) {
+    ($db, $dbapi) = $self->load_fast($geodb_opts);
+  }
 
-        if ($db->{$dbtype}) {
-          dbg("geodb: GeoIP2: loaded $dbtype from $path{$dbtype}");
+  if (!$db) {
+    dbg("geodb: No supported database could be loaded");
+    die("No supported GeoDB database could be loaded\n");
+  }
+
+  # country can be aliased to city
+  if (!$dbapi->{country} && $dbapi->{city}) {
+    $dbapi->{country} = $dbapi->{city};
+  }
+  if (!$dbapi->{country_v6} && $dbapi->{city_v6}) {
+    $dbapi->{country_v6} = $dbapi->{city_v6}
+  }
+
+  $self->{db} = $db;
+  $self->{dbapi} = $dbapi;
+
+  foreach (@{$self->get_dbinfo()}) {
+    dbg("geodb: database info: ".$_);
+  }
+  #dbg("geodb: apis available: ".join(', ', sort keys %{$self->{dbapi}}));
+
+  return 1;
+}
+
+sub load_geoip2 {
+  my ($self, $geodb_opts) = @_;
+  my ($db, $dbapi, $ok);
+
+  eval {
+    require GeoIP2::Database::Reader;
+  } or do {
+    dbg("geodb: GeoIP2::Database::Reader module load failed: $@");
+    return (undef, undef);
+  };
+
+  my %path;
+  foreach my $dbtype (@geoip_types) {
+    # only autosearch if no absolute path given
+    next if $geodb_opts->{dbs} && !exists $geodb_opts->{dbs}->{$dbtype};
+    # skip if not needed
+    next if $geodb_opts->{wanted} && !$geodb_opts->{wanted}->{$dbtype};
+    # skip country if city already loaded
+    next if $dbtype eq 'country' && $db->{city};
+    # skip asn if isp already loaded
+    next if $dbtype eq 'asn' && $db->{isp};
+    if (!defined $geodb_opts->{dbs}->{$dbtype}) {
+      # Try some default locations
+      PATHS_GEOIP2: foreach my $p (@{$geodb_opts->{search_path}}) {
+        foreach my $f (@{$geoip2_default_files{$dbtype}}) {
+          if (-f "$p/$f") {
+            $path{$dbtype} = "$p/$f";
+            dbg("geodb: GeoIP2: search found $dbtype $p/$f");
+            last PATHS_GEOIP2;
+          }
         }
       }
+    } else {
+      if (!-f $geodb_opts->{dbs}->{$dbtype}) {
+        dbg("geodb: GeoIP2: $dbtype database requested, but not found: ".
+          $geodb_opts->{dbs}->{$dbtype});
+        next;
+      }
+      $path{$dbtype} = $geodb_opts->{dbs}->{$dbtype};
     }
 
-    # dbinfo_DBTYPE()
-    $db->{city} and $dbapi->{dbinfo_city} = sub {
-      my $m = $_[0]->{db}->{city}->metadata;
-      return "GeoIP2 city: ".$m->description()->{en}." / ".localtime($m->build_epoch());
-    };
-    $db->{country} and $dbapi->{dbinfo_country} = sub {
-      my $m = $_[0]->{db}->{country}->metadata;
-      return "GeoIP2 country: ".$m->description()->{en}." / ".localtime($m->build_epoch());
-    };
-    $db->{isp} and $dbapi->{dbinfo_isp} = sub {
-      my $m = $_[0]->{db}->{isp}->metadata;
-      return "GeoIP2 isp: ".$m->description()->{en}." / ".localtime($m->build_epoch());
-    };
-    $db->{asn} and $dbapi->{dbinfo_asn} = sub {
-      my $m = $_[0]->{db}->{asn}->metadata;
-      return "GeoIP2 asn: ".$m->description()->{en}." / ".localtime($m->build_epoch());
-    };
-
-    # city()
-    $db->{city} and $dbapi->{city} = $dbapi->{city_v6} = sub {
-      my $res = {};
-      my $city;
-      eval {
-        $city = $_[0]->{db}->{city}->city(ip=>$_[1]);
-        1;
-      } or do {
-        $@ =~ s/\s+Trace begun.*//s;
-        dbg("geodb: GeoIP2 city query failed for $_[1]: $@");
-        return $res;
-      };
+    if (defined $path{$dbtype}) {
       eval {
-        $res->{city_name} = $city->{raw}->{city}->{names}->{en};
-        $res->{country} = $city->{raw}->{country}->{iso_code};
-        $res->{country_name} = $city->{raw}->{country}->{names}->{en};
-        $res->{continent} = $city->{raw}->{continent}->{code};
-        $res->{continent_name} = $city->{raw}->{continent}->{names}->{en};
+        $db->{$dbtype} = GeoIP2::Database::Reader->new(
+          file => $path{$dbtype},
+          locales => [ 'en' ]
+        );
+        die "unknown error" unless $db->{$dbtype};
         1;
       };
-      return $res;
-    };
-
-    # country()
-    $db->{country} and $dbapi->{country} = $dbapi->{country_v6} = sub {
-      my $res = {};
-      my $country;
-      eval {
-        $country = $_[0]->{db}->{country}->country(ip=>$_[1]);
-        1;
-      } or do {
+      if ($@ || !$db->{$dbtype}) {
         $@ =~ s/\s+Trace begun.*//s;
-        dbg("geodb: GeoIP2 country query failed for $_[1]: $@");
-        return $res;
-      };
-      eval {
-        $res->{country} = $country->{raw}->{country}->{iso_code};
-        $res->{country_name} = $country->{raw}->{country}->{names}->{en};
-        $res->{continent} = $country->{raw}->{continent}->{code};
-        $res->{continent_name} = $country->{raw}->{continent}->{names}->{en};
-        1;
-      };
+        dbg("geodb: GeoIP2: $dbtype load failed: $@");
+      } else {
+        dbg("geodb: GeoIP2: loaded $dbtype from $path{$dbtype}");
+        $ok = 1;
+      }
+    } else {
+      my $from = defined $geodb_opts->{dbs}->{$dbtype} ?
+        $geodb_opts->{dbs}->{$dbtype} : "default locations";
+      dbg("geodb: GeoIP2: $dbtype database not found from $from");
+    } 
+  }
+
+  return (undef, undef) if !$ok;
+
+  # dbinfo_DBTYPE()
+  $db->{city} and $dbapi->{dbinfo_city} = sub {
+    my $m = $_[0]->{db}->{city}->metadata;
+    return "GeoIP2 city: ".$m->description()->{en}." / ".localtime($m->build_epoch());
+  };
+  $db->{country} and $dbapi->{dbinfo_country} = sub {
+    my $m = $_[0]->{db}->{country}->metadata;
+    return "GeoIP2 country: ".$m->description()->{en}." / ".localtime($m->build_epoch());
+  };
+  $db->{isp} and $dbapi->{dbinfo_isp} = sub {
+    my $m = $_[0]->{db}->{isp}->metadata;
+    return "GeoIP2 isp: ".$m->description()->{en}." / ".localtime($m->build_epoch());
+  };
+  $db->{asn} and $dbapi->{dbinfo_asn} = sub {
+    my $m = $_[0]->{db}->{asn}->metadata;
+    return "GeoIP2 asn: ".$m->description()->{en}." / ".localtime($m->build_epoch());
+  };
+
+  # city()
+  $db->{city} and $dbapi->{city} = $dbapi->{city_v6} = sub {
+    my $res = {};
+    my $city;
+    eval {
+      $city = $_[0]->{db}->{city}->city(ip=>$_[1]);
+      1;
+    } or do {
+      $@ =~ s/\s+Trace begun.*//s;
+      dbg("geodb: GeoIP2 city query failed for $_[1]: $@");
       return $res;
     };
+    eval {
+      $res->{city_name} = $city->{raw}->{city}->{names}->{en};
+      $res->{country} = $city->{raw}->{country}->{iso_code};
+      $res->{country_name} = $city->{raw}->{country}->{names}->{en};
+      $res->{continent} = $city->{raw}->{continent}->{code};
+      $res->{continent_name} = $city->{raw}->{continent}->{names}->{en};
+      1;
+    };
+    return $res;
+  };
 
-    # isp()
-    $db->{isp} and $dbapi->{isp} = $dbapi->{isp_v6} = sub {
-      my $res = {};
-      my $isp;
-      eval {
-        $isp = $_[0]->{db}->{isp}->isp(ip=>$_[1]);
-        1;
-      } or do {
-        $@ =~ s/\s+Trace begun.*//s;
-        dbg("geodb: GeoIP2 isp query failed for $_[1]: $@");
-        return $res;
-      };
-      eval {
-        $res->{asn} = $isp->autonomous_system_number();
-        $res->{asn_organization} = $isp->autonomous_system_organization();
-        $res->{isp} = $isp->isp();
-        $res->{organization} = $isp->organization();
-        1;
-      };
+  # country()
+  $db->{country} and $dbapi->{country} = $dbapi->{country_v6} = sub {
+    my $res = {};
+    my $country;
+    eval {
+      $country = $_[0]->{db}->{country}->country(ip=>$_[1]);
+      1;
+    } or do {
+      $@ =~ s/\s+Trace begun.*//s;
+      dbg("geodb: GeoIP2 country query failed for $_[1]: $@");
       return $res;
     };
+    eval {
+      $res->{country} = $country->{raw}->{country}->{iso_code};
+      $res->{country_name} = $country->{raw}->{country}->{names}->{en};
+      $res->{continent} = $country->{raw}->{continent}->{code};
+      $res->{continent_name} = $country->{raw}->{continent}->{names}->{en};
+      1;
+    };
+    return $res;
+  };
 
-    # asn()
-    $db->{asn} and $dbapi->{asn} = $dbapi->{asn_v6} = sub {
-      my $res = {};
-      my $asn;
-      eval {
-        $asn = $_[0]->{db}->{asn}->asn(ip=>$_[1]);
-        1;
-      } or do {
-        $@ =~ s/\s+Trace begun.*//s;
-        dbg("geodb: GeoIP2 asn query failed for $_[1]: $@");
-        return $res;
-      };
-      eval {
-        $res->{asn} = $asn->autonomous_system_number();
-        $res->{asn_organization} = $asn->autonomous_system_organization();
-        1;
-      };
+  # isp()
+  $db->{isp} and $dbapi->{isp} = $dbapi->{isp_v6} = sub {
+    my $res = {};
+    my $isp;
+    eval {
+      $isp = $_[0]->{db}->{isp}->isp(ip=>$_[1]);
+      1;
+    } or do {
+      $@ =~ s/\s+Trace begun.*//s;
+      dbg("geodb: GeoIP2 isp query failed for $_[1]: $@");
       return $res;
     };
-  }
-
-  ##
-  ## Geo::IP
-  ##
+    eval {
+      $res->{asn} = $isp->autonomous_system_number();
+      $res->{asn_organization} = $isp->autonomous_system_organization();
+      $res->{isp} = $isp->isp();
+      $res->{organization} = $isp->organization();
+      1;
+    };
+    return $res;
+  };
 
-  if (!$db && (!$geodb_module || $geodb_module eq 'geoip')) {
-    my $prep_ok = 0;
-    my ($gic_wanted,$gic_have,$gip_wanted,$gip_have);
-    my ($flags,$fix_stderr,$can_ipv6);
-    eval {
-      require Geo::IP;
-      # need GeoIP C library 1.6.3 and GeoIP perl API 1.4.4 or later to avoid messages leaking - Bug 7153
-      $gip_wanted = version->parse('v1.4.4');
-      $gip_have = version->parse(Geo::IP->VERSION);
-      $gic_wanted = version->parse('v1.6.3');
-      eval { $gic_have = version->parse(Geo::IP->lib_version()); }; # might not have lib_version()
-      $gic_have = 'none' if !defined $gic_have;
-      dbg("geodb: GeoIP: versions: Geo::IP $gip_have, C library $gic_have");
-      $flags = 0;
-      $fix_stderr = 0;
-      if (ref($gic_have) eq 'version') {
-        # this code burps an ugly message if it fails, but that's redirected elsewhere
-        eval '$flags = Geo::IP::GEOIP_SILENCE' if $gip_wanted >= $gip_have;
-        $fix_stderr = $flags && $gic_wanted >= $gic_have;
-      }
-      $can_ipv6 = Geo::IP->VERSION >= 1.39 && Geo::IP->api eq 'CAPI';
-      $prep_ok = 1;
+  # asn()
+  $db->{asn} and $dbapi->{asn} = $dbapi->{asn_v6} = sub {
+    my $res = {};
+    my $asn;
+    eval {
+      $asn = $_[0]->{db}->{asn}->asn(ip=>$_[1]);
       1;
     } or do {
-      dbg("geodb: Geo::IP module load failed: $@");
+      $@ =~ s/\s+Trace begun.*//s;
+      dbg("geodb: GeoIP2 asn query failed for $_[1]: $@");
+      return $res;
     };
+    eval {
+      $res->{asn} = $asn->autonomous_system_number();
+      $res->{asn_organization} = $asn->autonomous_system_organization();
+      1;
+    };
+    return $res;
+  };
 
-    if ($prep_ok) {
-      my %path;
+  return ($db, $dbapi);
+}
 
-      foreach my $dbtype (@geoip_types) {
-        # only autosearch if no absolute path given
-        next if %$geodb_dbs && !exists $geodb_dbs->{$dbtype};
-        # skip if not needed
-        next if %$geodb_wanted && !$geodb_wanted->{$dbtype};
-        # skip country if city already loaded
-        next if $dbtype eq 'country' && $db->{city};
-        # skip asn if isp already loaded
-        next if $dbtype eq 'asn' && $db->{isp};
-        if (!defined $geodb_dbs->{$dbtype}) {
-          # Try some default locations
-          PATHS_GEOIP: foreach my $p (@geoip_search_path) {
-            foreach my $f (@{$geoip_default_files{$dbtype}}) {
+sub load_geoip {
+  my ($self, $geodb_opts) = @_;
+  my ($db, $dbapi, $ok);
+  my ($gic_wanted, $gic_have, $gip_wanted, $gip_have);
+  my ($flags, $fix_stderr, $can_ipv6);
+
+  eval {
+    require Geo::IP;
+    # need GeoIP C library 1.6.3 and GeoIP perl API 1.4.4 or later to avoid messages leaking - Bug 7153
+    $gip_wanted = version->parse('v1.4.4');
+    $gip_have = version->parse(Geo::IP->VERSION);
+    $gic_wanted = version->parse('v1.6.3');
+    eval { $gic_have = version->parse(Geo::IP->lib_version()); }; # might not have lib_version()
+    $gic_have = 'none' if !defined $gic_have;
+    dbg("geodb: GeoIP: versions: Geo::IP $gip_have, C library $gic_have");
+    $flags = 0;
+    $fix_stderr = 0;
+    if (ref($gic_have) eq 'version') {
+      # this code burps an ugly message if it fails, but that's redirected elsewhere
+      eval '$flags = Geo::IP::GEOIP_SILENCE' if $gip_wanted >= $gip_have;
+      $fix_stderr = $flags && $gic_wanted >= $gic_have;
+    }
+    $can_ipv6 = Geo::IP->VERSION >= 1.39 && Geo::IP->api eq 'CAPI';
+    1;
+  } or do {
+    dbg("geodb: Geo::IP module load failed: $@");
+    return (undef, undef);
+  };
+
+  my %path;
+  foreach my $dbtype (@geoip_types) {
+    # only autosearch if no absolute path given
+    next if $geodb_opts->{dbs} && !exists $geodb_opts->{dbs}->{$dbtype};
+    # skip if not needed
+    next if $geodb_opts->{wanted} && !$geodb_opts->{wanted}->{$dbtype};
+    # skip country if city already loaded
+    next if $dbtype eq 'country' && $db->{city};
+    # skip asn if isp already loaded
+    next if $dbtype eq 'asn' && $db->{isp};
+    if (!defined $geodb_opts->{dbs}->{$dbtype}) {
+      # Try some default locations
+      PATHS_GEOIP: foreach my $p (@{$geodb_opts->{search_path}}) {
+        foreach my $f (@{$geoip_default_files{$dbtype}}) {
+          if (-f "$p/$f") {
+            $path{$dbtype} = "$p/$f";
+            dbg("geodb: GeoIP: search found $dbtype $p/$f");
+            if ($can_ipv6 && $f =~ s/\.(dat)$/v6.$1/i) {
               if (-f "$p/$f") {
-                $path{$dbtype} = "$p/$f";
+                $path{$dbtype."_v6"} = "$p/$f";
                 dbg("geodb: GeoIP: search found $dbtype $p/$f");
-                if ($can_ipv6 && $f =~ s/\.(dat)$/v6.$1/i) {
-                  if (-f "$p/$f") {
-                    $path{$dbtype."_v6"} = "$p/$f";
-                    dbg("geodb: GeoIP: search found $dbtype $p/$f");
-                  }
-                }
-                last PATHS_GEOIP;
               }
             }
+            last PATHS_GEOIP;
           }
-        } else {
-          if (!-f $geodb_dbs->{$dbtype}) {
-            dbg("geodb: GeoIP: $dbtype database requested, but not found: ".$geodb_dbs->{$dbtype});
-            next;
-          }
-          $path{$dbtype} = $geodb_dbs->{$dbtype};
         }
       }
-
-      if (!$can_ipv6) {
-        dbg("geodb: GeoIP: IPv6 support not enabled, versions Geo::IP 1.39, GeoIP C API 1.4.7 required");
-      }
-
-      if ($fix_stderr) {
-        open(OLDERR, ">&STDERR");
-        open(STDERR, ">/dev/null");
-      }
-      foreach my $dbtype (@geoip_types) {
-        next unless defined $path{$dbtype};
-        eval {
-          $db->{$dbtype} = Geo::IP->open($path{$dbtype}, Geo::IP->GEOIP_STANDARD | $flags);
-          if ($can_ipv6 && defined $path{$dbtype."_v6"}) {
-            $db->{$dbtype."_v6"} = Geo::IP->open($path{$dbtype."_v6"}, Geo::IP->GEOIP_STANDARD | $flags);
-          }
-        };
-        if ($@ || !$db->{$dbtype}) {
-          dbg("geodb: GeoIP: database $path{$dbtype} load failed: $@");
-        };
-      }
-      if ($fix_stderr) {
-        open(STDERR, ">&OLDERR");
-        close(OLDERR);
+    } else {
+      if (!-f $geodb_opts->{dbs}->{$dbtype}) {
+        dbg("geodb: GeoIP: $dbtype database requested, but not found: ".
+          $geodb_opts->{dbs}->{$dbtype});
+        next;
       }
+      $path{$dbtype} = $geodb_opts->{dbs}->{$dbtype};
     }
-
-    # dbinfo_DBTYPE()
-    $db->{city} and $dbapi->{dbinfo_city} = sub {
-      return "Geo::IP IPv4 city: " . ($_[0]->{db}->{city}->database_info || '?')." / IPv6: ".
-        ($_[0]->{db}->{city_v6} ? $_[0]->{db}->{city_v6}->database_info || '?' : 'no')
-    };
-    $db->{country} and $dbapi->{dbinfo_country} = sub {
-      return "Geo::IP IPv4 country: " . ($_[0]->{db}->{country}->database_info || '?')." / IPv6: ".
-        ($_[0]->{db}->{country_v6} ? $_[0]->{db}->{country_v6}->database_info || '?' : 'no')
-    };
-    $db->{isp} and $dbapi->{dbinfo_isp} = sub {
-      return "Geo::IP IPv4 isp: " . ($_[0]->{db}->{isp}->database_info || '?')." / IPv6: ".
-        ($_[0]->{db}->{isp_v6} ? $_[0]->{db}->{isp_v6}->database_info || '?' : 'no')
-    };
-    $db->{asn} and $dbapi->{dbinfo_asn} = sub {
-      return "Geo::IP IPv4 asn: " . ($_[0]->{db}->{asn}->database_info || '?')." / IPv6: ".
-        ($_[0]->{db}->{asn_v6} ? $_[0]->{db}->{asn_v6}->database_info || '?' : 'no')
-    };
-
-    # city()
-    $db->{city} and $dbapi->{city} = sub {
-      my $res = {};
-      my $city;
-      if ($_[1] =~ /^$IPV4_ADDRESS$/o) {
-        $city = $_[0]->{db}->{city}->record_by_addr($_[1]);
-      } elsif ($_[0]->{db}->{city_v6}) {
-        $city = $_[0]->{db}->{city_v6}->country_code_by_addr_v6($_[1]);
-        return $res if !defined $city;
-        $res->{country} = $city;
-        return $res;
-      }
-      if (!defined $city) {
-        dbg("geodb: GeoIP city query failed for $_[1]");
-        return $res;
-      }
-      $res->{city_name} = $city->city;
-      $res->{country} = $city->country_code;
-      $res->{country_name} = $city->country_name;
-      $res->{continent} = $city->continent_code;
-      return $res;
-    };
-    $dbapi->{city_v6} = $dbapi->{city} if $db->{city_v6};
-
-    # country()
-    $db->{country} and $dbapi->{country} = sub {
-      my $res = {};
-      my $country;
-      eval {
-        if ($_[1] =~ /^$IPV4_ADDRESS$/o) {
-          $country = $_[0]->{db}->{country}->country_code_by_addr($_[1]);
-        } elsif ($_[0]->{db}->{country_v6}) {
-          $country = $_[0]->{db}->{country_v6}->country_code_by_addr_v6($_[1]);
-        }
-        1;
-      };
-      if (!defined $country) {
-        dbg("geodb: GeoIP country query failed for $_[1]");
-        return $res;
-      };
-      $res->{country} = $country;
-      $res->{continent} = $country_to_continent{$country} || 'XX';
-      return $res;
-    };
-    $dbapi->{country_v6} = $dbapi->{country} if $db->{country_v6};
-
-    # isp()
-    $db->{isp} and $dbapi->{isp} = sub {
-      my $res = {};
-      my $isp;
-      eval {
-        if ($_[1] =~ /^$IPV4_ADDRESS$/o) {
-          $isp = $_[0]->{db}->{isp}->isp_by_addr($_[1]);
-        } else {
-          # TODO?
-          return $res;
-        }
-        1;
-      };
-      if (!defined $isp) {
-        dbg("geodb: GeoIP isp query failed for $_[1]");
-        return $res;
-      };
-      $res->{isp} = $isp;
-      return $res;
-    };
   }
 
-  ##
-  ## IP::Country::DB_File
-  ##
+  if (!$can_ipv6) {
+    dbg("geodb: GeoIP: IPv6 support not enabled, versions Geo::IP 1.39, GeoIP C API 1.4.7 required");
+  }
 
-  # Only try if geodb_module and path to ipcc.db specified
-  if (!$db && $geodb_module eq 'dbfile') {
-    if (defined $geodb_dbs->{country}) {
-      if (-f $geodb_dbs->{country}) {
-        eval {
-          require IP::Country::DB_File;
-          $db->{country} = IP::Country::DB_File->new($geodb_dbs->{country});
-          1;
-        };
-        if ($@ || !$db->{country}) {
-          dbg("geodb: IP::Country::DB_File country load failed: $@");
-        } else {
-          dbg("geodb: IP::Country::DB_File loaded country from ".$geodb_dbs->{country});
-        }
-      } else {
-        dbg("geodb: IP::Country::DB_File database not found: ".$geodb_dbs->{country});
+  if ($fix_stderr) {
+    open(OLDERR, ">&STDERR");
+    open(STDERR, ">/dev/null");
+  }
+  foreach my $dbtype (@geoip_types) {
+    next unless defined $path{$dbtype};
+    eval {
+      $db->{$dbtype} = Geo::IP->open($path{$dbtype}, Geo::IP->GEOIP_STANDARD | $flags);
+      if ($can_ipv6 && defined $path{$dbtype."_v6"}) {
+        $db->{$dbtype."_v6"} = Geo::IP->open($path{$dbtype."_v6"}, Geo::IP->GEOIP_STANDARD | $flags);
       }
+    };
+    if ($@ || !$db->{$dbtype}) {
+      dbg("geodb: GeoIP: database $path{$dbtype} load failed: $@");
     } else {
-      dbg("geodb: IP::Country::DB_File requires geodb_options country:/path/to/ipcc.db");
+      dbg("geodb: GeoIP: loaded $dbtype from $path{$dbtype}");
+      $ok = 1;
     }
+  }
+  if ($fix_stderr) {
+    open(STDERR, ">&OLDERR");
+    close(OLDERR);
+  }
 
-    # dbinfo_DBTYPE()
-    $db->{country} and $dbapi->{dbinfo_country} = sub {
-      return "IP::Country::DB_File country: ".localtime($_[0]->{db}->{country}->db_time());
-    };
+  return (undef, undef) if !$ok;
 
-    # country();
-    $db->{country} and $dbapi->{country} = $dbapi->{country_v6} = sub {
-      my $res = {};
-      my $country;
-      if ($_[1] =~ /^$IPV4_ADDRESS$/o) {
-        $country = $_[0]->{db}->{country}->inet_atocc($_[1]);
-      } else {
-        $country = $_[0]->{db}->{country}->inet6_atocc($_[1]);
-      }
-      if (!defined $country) {
-        dbg("geodb: IP::Country::DB_File country query failed for $_[1]");
-        return $res;
-      };
-      $res->{country} = $country;
-      $res->{continent} = $country_to_continent{$country} || 'XX';
+  # dbinfo_DBTYPE()
+  $db->{city} and $dbapi->{dbinfo_city} = sub {
+    return "Geo::IP IPv4 city: " . ($_[0]->{db}->{city}->database_info || '?')." / IPv6: ".
+      ($_[0]->{db}->{city_v6} ? $_[0]->{db}->{city_v6}->database_info || '?' : 'no')
+  };
+  $db->{country} and $dbapi->{dbinfo_country} = sub {
+    return "Geo::IP IPv4 country: " . ($_[0]->{db}->{country}->database_info || '?')." / IPv6: ".
+      ($_[0]->{db}->{country_v6} ? $_[0]->{db}->{country_v6}->database_info || '?' : 'no')
+  };
+  $db->{isp} and $dbapi->{dbinfo_isp} = sub {
+    return "Geo::IP IPv4 isp: " . ($_[0]->{db}->{isp}->database_info || '?')." / IPv6: ".
+      ($_[0]->{db}->{isp_v6} ? $_[0]->{db}->{isp_v6}->database_info || '?' : 'no')
+  };
+  $db->{asn} and $dbapi->{dbinfo_asn} = sub {
+    return "Geo::IP IPv4 asn: " . ($_[0]->{db}->{asn}->database_info || '?')." / IPv6: ".
+      ($_[0]->{db}->{asn_v6} ? $_[0]->{db}->{asn_v6}->database_info || '?' : 'no')
+  };
+
+  # city()
+  $db->{city} and $dbapi->{city} = sub {
+    my $res = {};
+    my $city;
+    if ($_[1] =~ /^$IPV4_ADDRESS$/o) {
+      $city = $_[0]->{db}->{city}->record_by_addr($_[1]);
+    } elsif ($_[0]->{db}->{city_v6}) {
+      $city = $_[0]->{db}->{city_v6}->country_code_by_addr_v6($_[1]);
+      return $res if !defined $city;
+      $res->{country} = $city;
       return $res;
-    };
-  } 
-
-  ##
-  ## IP::Country::Fast
-  ##
-
-  if (!$db && (!$geodb_module || $geodb_module eq 'fast')) {
+    }
+    if (!defined $city) {
+      dbg("geodb: GeoIP city query failed for $_[1]");
+      return $res;
+    }
+    $res->{city_name} = $city->city;
+    $res->{country} = $city->country_code;
+    $res->{country_name} = $city->country_name;
+    $res->{continent} = $city->continent_code;
+    return $res;
+  };
+  $dbapi->{city_v6} = $dbapi->{city} if $db->{city_v6};
+
+  # country()
+  $db->{country} and $dbapi->{country} = sub {
+    my $res = {};
+    my $country;
     eval {
-      require IP::Country::Fast;
-      $db->{country} = IP::Country::Fast->new();
+      if ($_[1] =~ /^$IPV4_ADDRESS$/o) {
+        $country = $_[0]->{db}->{country}->country_code_by_addr($_[1]);
+      } elsif ($_[0]->{db}->{country_v6}) {
+        $country = $_[0]->{db}->{country_v6}->country_code_by_addr_v6($_[1]);
+      }
       1;
     };
-    if ($@ || !$db->{country}) {
-      my $eval_stat = $@ ne '' ? $@ : "errno=$!";  chomp $eval_stat;
-      dbg("geodb: IP::Country::Fast load failed: $eval_stat");
-    }
-
-    # dbinfo_DBTYPE()
-    $db->{country} and $dbapi->{dbinfo_country} = sub {
-      return "IP::Country::Fast country: ".localtime($_[0]->{db}->{country}->db_time());
+    if (!defined $country) {
+      dbg("geodb: GeoIP country query failed for $_[1]");
+      return $res;
     };
-
-    # country();
-    $db->{country} and $dbapi->{country} = sub {
-      my $res = {};
-      my $country;
+    $res->{country} = $country;
+    $res->{continent} = $country_to_continent{$country} || 'XX';
+    return $res;
+  };
+  $dbapi->{country_v6} = $dbapi->{country} if $db->{country_v6};
+
+  # isp()
+  $db->{isp} and $dbapi->{isp} = sub {
+    my $res = {};
+    my $isp;
+    eval {
       if ($_[1] =~ /^$IPV4_ADDRESS$/o) {
-        $country = $_[0]->{db}->{country}->inet_atocc($_[1]);
+        $isp = $_[0]->{db}->{isp}->isp_by_addr($_[1]);
       } else {
-        return $res
+        # TODO?
+        return $res;
       }
-      $res->{country} = $country;
-      $res->{continent} = $country_to_continent{$country} || 'XX';
+      1;
+    };
+    if (!defined $isp) {
+      dbg("geodb: GeoIP isp query failed for $_[1]");
       return $res;
     };
-  }
+    $res->{isp} = $isp;
+    return $res;
+  };
 
-  ##
+  return ($db, $dbapi);
+}
 
-  if (!%$db) {
-    dbg("geodb: No supported database could be loaded");
-    die("No supported GeoDB database could be loaded\n");
+sub load_dbfile {
+  my ($self, $geodb_opts) = @_;
+  my ($db, $dbapi);
+
+  if (!defined $geodb_opts->{dbs}->{country}) {
+    dbg("geodb: IP::Country::DB_File requires geodb_options country:/path/to/ipcc.db");
+    return (undef, undef);
   }
 
-  # country can be aliased to city
-  if (!$dbapi->{country} && $dbapi->{city}) {
-    $dbapi->{country} = $dbapi->{city};
+  if (!-f $geodb_opts->{dbs}->{country}) {
+    dbg("geodb: IP::Country::DB_File database not found: ".$geodb_opts->{dbs}->{country});
+    return (undef, undef);
   }
-  if (!$dbapi->{country_v6} && $dbapi->{city_v6}) {
-    $dbapi->{country_v6} = $dbapi->{city_v6}
+
+  eval {
+    require IP::Country::DB_File;
+    $db->{country} = IP::Country::DB_File->new($geodb_opts->{dbs}->{country});
+    1;
+  };
+  if ($@ || !$db->{country}) {
+    dbg("geodb: IP::Country::DB_File country load failed: $@");
+    return (undef, undef);
+  } else {
+    dbg("geodb: IP::Country::DB_File loaded country from ".$geodb_opts->{dbs}->{country});
   }
 
-  $self->{db} = $db;
-  $self->{dbapi} = $dbapi;
+  # dbinfo_DBTYPE()
+  $db->{country} and $dbapi->{dbinfo_country} = sub {
+    return "IP::Country::DB_File country: ".localtime($_[0]->{db}->{country}->db_time());
+  };
+
+  # country();
+  $db->{country} and $dbapi->{country} = $dbapi->{country_v6} = sub {
+    my $res = {};
+    my $country;
+    if ($_[1] =~ /^$IPV4_ADDRESS$/o) {
+      $country = $_[0]->{db}->{country}->inet_atocc($_[1]);
+    } else {
+      $country = $_[0]->{db}->{country}->inet6_atocc($_[1]);
+    }
+    if (!defined $country) {
+      dbg("geodb: IP::Country::DB_File country query failed for $_[1]");
+      return $res;
+    };
+    $res->{country} = $country;
+    $res->{continent} = $country_to_continent{$country} || 'XX';
+    return $res;
+  };
 
-  foreach (@{$self->get_dbinfo()}) {
-    dbg("geodb: database info: ".$_);
+  return ($db, $dbapi);
+}
+
+sub load_fast {
+  my ($self, $geodb_opts) = @_;
+  my ($db, $dbapi);
+
+  eval {
+    require IP::Country::Fast;
+    $db->{country} = IP::Country::Fast->new();
+    1;
+  };
+  if ($@ || !$db->{country}) {
+    my $eval_stat = $@ ne '' ? $@ : "errno=$!";  chomp $eval_stat;
+    dbg("geodb: IP::Country::Fast load failed: $eval_stat");
+    return (undef, undef);
   }
-  #dbg("geodb: apis available: ".join(', ', sort keys %{$self->{dbapi}}));
 
-  return 1;
+  # dbinfo_DBTYPE()
+  $db->{country} and $dbapi->{dbinfo_country} = sub {
+    return "IP::Country::Fast country: ".localtime($_[0]->{db}->{country}->db_time());
+  };
+
+  # country();
+  $db->{country} and $dbapi->{country} = sub {
+    my $res = {};
+    my $country;
+    if ($_[1] =~ /^$IPV4_ADDRESS$/o) {
+      $country = $_[0]->{db}->{country}->inet_atocc($_[1]);
+    } else {
+      return $res
+    }
+    $res->{country} = $country;
+    $res->{continent} = $country_to_continent{$country} || 'XX';
+    return $res;
+  };
+
+  return ($db, $dbapi);
 }
 
 # return array, infoline per database type

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/RelayCountry.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/RelayCountry.pm?rev=1843928&r1=1843927&r2=1843928&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/RelayCountry.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/RelayCountry.pm Mon Oct 15 17:33:59 2018
@@ -41,7 +41,6 @@ package Mail::SpamAssassin::Plugin::Rela
 
 use Mail::SpamAssassin::Plugin;
 use Mail::SpamAssassin::Logger;
-use Mail::SpamAssassin::GeoDB;
 use strict;
 use warnings;
 # use bytes;
@@ -64,6 +63,9 @@ sub new {
   my $self = $class->SUPER::new($mailsaobject);
   bless ($self, $class);
 
+  # we need GeoDB country
+  $self->{main}->{geodb_wanted}->{country} = 1;
+
   return $self;
 }
 
@@ -72,27 +74,20 @@ sub extract_metadata {
   
   return if $self->{relaycountry_disabled};
 
-  if (!$self->{geodb}) {
-    eval {
-      $self->{geodb} = Mail::SpamAssassin::GeoDB->new({
-        conf => $opts->{conf}->{geodb},
-        wanted => { country => 1, city => 1 },
-      });
-    };
-    if (!$self->{geodb}) {
-      dbg("metadata: RelayCountry: plugin disabled: $@");
-      $self->{relaycountry_disabled} = 1;
-      return;
-    }
+  if (!$self->{main}->{geodb} ||
+        !$self->{main}->{geodb}->can('country')) {
+    dbg("metadata: RelayCountry: plugin disabled, GeoDB country not available");
+    $self->{relaycountry_disabled} = 1;
+    return;
   }
 
-  my $geodb = $self->{geodb};
   my $msg = $opts->{msg};
+  my $geodb = $self->{main}->{geodb};
 
   my $countries = '';
   foreach my $relay (@{$msg->{metadata}->{relays_untrusted}}) {
     my $ip = $relay->{ip};
-    my $cc = $self->{geodb}->get_country($ip);
+    my $cc = $geodb->get_country($ip);
     $countries .= $cc." ";
   }
 
@@ -104,7 +99,7 @@ sub extract_metadata {
 sub parsed_metadata {
   my ($self, $opts) = @_;
 
-  return 1 unless $self->{geodb};
+  return 1 if $self->{relaycountry_disabled};
 
   my $countries =
     $opts->{permsgstatus}->get_message->get_metadata('X-Relay-Countries');

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/URILocalBL.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/URILocalBL.pm?rev=1843928&r1=1843927&r2=1843928&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/URILocalBL.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/URILocalBL.pm Mon Oct 15 17:33:59 2018
@@ -108,7 +108,6 @@ package Mail::SpamAssassin::Plugin::URIL
 use Mail::SpamAssassin::Plugin;
 use Mail::SpamAssassin::Constants qw(:ip);
 use Mail::SpamAssassin::Util qw(untaint_var idn_to_ascii);
-use Mail::SpamAssassin::GeoDB;
 use Mail::SpamAssassin::NetSet;
 
 use Socket;
@@ -142,6 +141,10 @@ sub new {
   $self->register_eval_rule("check_uri_local_bl");
   $self->set_config($mailsaobject->{conf});
 
+  # we need GeoDB country/isp
+  $self->{main}->{geodb_wanted}->{country} = 1;
+  $self->{main}->{geodb_wanted}->{isp} = 1;
+
   return $self;
 }
 
@@ -339,29 +342,18 @@ sub finish_parsing_end {
   }
 }
 
-sub _init_geodb {
-  my ($self, $pms) = @_;
-  if (!$self->{geodb}) {
-    eval {
-      $self->{geodb} = Mail::SpamAssassin::GeoDB->new({
-        conf => $pms->{conf}->{geodb},
-        wanted => { country => 1, city => 1, isp => 1 },
-      });
-    };
-    if (!$self->{geodb}) {
-      dbg("plugin disabled: $@");
-      $self->{urilocalbl_disabled} = 1;
-      return 0;
-    }
-  }
-  return 1;
-}
-
 sub check_uri_local_bl {
   my ($self, $pms) = @_;
 
   return 0 if $self->{urilocalbl_disabled};
-  return 0 if !$self->_init_geodb($pms);
+
+  if (!$self->{main}->{geodb} ||
+        (!$self->{main}->{geodb}->can('country') &&
+         !$self->{main}->{geodb}->can('isp'))) {
+    dbg("plugin disabled, GeoDB country/isp not available");
+    $self->{urilocalbl_disabled} = 1;
+    return 0;
+  }
 
   my $rulename = $pms->get_current_eval_rule_name();
   my $ruleconf = $pms->{conf}->{urilocalbl}->{$rulename};
@@ -414,7 +406,7 @@ sub check_uri_local_bl {
       sub { my($ent, $pkt) = @_;
             $self->_finish_lookup($pms, $ent, $pkt); },
       master_deadline => $pms->{master_deadline}
-    ) if $self->{geodb}->can('country_v6');
+    ) if $self->{main}->{geodb}->can('country_v6');
   }
 }
 
@@ -453,6 +445,7 @@ sub _check_host {
   my ($self, $pms, $rulename, $host, $addrs) = @_;
 
   my $ruleconf = $pms->{conf}->{urilocalbl}->{$rulename};
+  my $geodb = $self->{main}->{geodb};
 
   if ($host ne $addrs->[0]) {
     dbg("resolved $host: ".join(', ', @$addrs));
@@ -474,7 +467,7 @@ sub _check_host {
       dbg("checking $host for countries: $testcc");
     }
     foreach my $ip (@$addrs) {
-      my $cc = $self->{geodb}->get_country($ip);
+      my $cc = $geodb->get_country($ip);
       if ( (!$neg && defined $ruleconf->{countries}{$cc}) ||
            ($neg && !defined $ruleconf->{countries}{$cc}) ) {
         dbg("$host ($ip) country $cc - HIT");
@@ -496,7 +489,7 @@ sub _check_host {
       dbg("checking $host for continents: $testcont");
     }
     foreach my $ip (@$addrs) {
-      my $cc = $self->{geodb}->get_continent($ip);
+      my $cc = $geodb->get_continent($ip);
       if ( (!$neg && defined $ruleconf->{continents}{$cc}) ||
            ($neg && !defined $ruleconf->{continents}{$cc}) ) {
         dbg("$host ($ip) continent $cc - HIT");
@@ -510,12 +503,12 @@ sub _check_host {
   }
 
   if (defined $ruleconf->{isps}) {
-    if ($self->{geodb}->can('isp')) {
+    if ($geodb->can('isp')) {
       my $testisp = join(', ', map {"\"$_\""} sort values %{$ruleconf->{isps}});
       dbg("checking $host for isps: $testisp");
 
       foreach my $ip (@$addrs) {
-        my $isp = $self->{geodb}->get_isp($ip);
+        my $isp = $geodb->get_isp($ip);
         next unless defined $isp;
         my $ispkey = uc($isp); $ispkey =~ s/\s+//gs;
         if (defined $ruleconf->{isps}{$ispkey}) {