From: Laurent Destailleur Date: Sat, 8 Feb 2014 10:52:16 +0000 (+0100) Subject: New: #199 Added geoip6 plugin with support for IPv4 AND IPv6 X-Git-Tag: AWSTATS_7_4~26 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=74082d3325427c74dbcb16d22638b6b8cfa2448a;p=thirdparty%2FAWStats.git New: #199 Added geoip6 plugin with support for IPv4 AND IPv6 --- diff --git a/docs/awstats_changelog.txt b/docs/awstats_changelog.txt index a0c0099d..ba2f740b 100644 --- a/docs/awstats_changelog.txt +++ b/docs/awstats_changelog.txt @@ -6,6 +6,7 @@ AWStats Changelog New features: - Add debian patch debian-patches-1019_allow_frame_resize.patch to add option nboflastupdatelookuptosave on command line. +- #199 Added geoip6 plugin with support for IPv4 AND IPv6. Fixes: - Fixes permission on some .pl scripts. diff --git a/wwwroot/cgi-bin/awstats.model.conf b/wwwroot/cgi-bin/awstats.model.conf index b152870d..ab473e45 100644 --- a/wwwroot/cgi-bin/awstats.model.conf +++ b/wwwroot/cgi-bin/awstats.model.conf @@ -1442,6 +1442,16 @@ color_x="C1B2E2" # Background color for number of exit pages (Default = "C1B2 # #LoadPlugin="geoip GEOIP_STANDARD /pathto/GeoIP.dat" +# PLUGIN: GeoIP6 +# REQUIRED MODULES: Geo::IP or Geo::IP::PurePerl (from Maxmind, version >= 1.40) +# PARAMETERS: [GEOIP_STANDARD | GEOIP_MEMORY_CACHE] [/pathto/geoipv6.dat[+/pathto/override.txt]] +# DESCRIPTION: Builds a country chart and adds an entry to the hosts +# table with country name +# works with IPv4 and also IPv6 addresses +# Replace spaces in the path of geoip data file with string "%20". +# +#LoadPlugin="geoip6 GEOIP_STANDARD /pathto/GeoIPv6.dat" + # PLUGIN: GeoIP_City_Maxmind # REQUIRED MODULES: Geo::IP or Geo::IP::PurePerl (from Maxmind) # PARAMETERS: [GEOIP_STANDARD | GEOIP_MEMORY_CACHE] [/pathto/GeoIPCity.dat[+/pathto/override.txt]] diff --git a/wwwroot/cgi-bin/awstats.pl b/wwwroot/cgi-bin/awstats.pl index 7df54070..fdb8bcc6 100755 --- a/wwwroot/cgi-bin/awstats.pl +++ b/wwwroot/cgi-bin/awstats.pl @@ -3118,6 +3118,7 @@ sub Read_Plugins { 'hashfiles' => 'u', 'geoipfree' => 'u', 'geoip' => 'ou', + 'geoip6' => 'ou', 'geoip_region_maxmind' => 'mou', 'geoip_city_maxmind' => 'mou', 'geoip_isp_maxmind' => 'mou', @@ -3293,6 +3294,7 @@ sub Read_Plugins { # In output mode, geo ip plugins are not loaded, so message changes are done here (can't be done in plugin init function) if ( $PluginsLoaded{'init'}{'geoip'} + || $PluginsLoaded{'init'}{'geoip6'} || $PluginsLoaded{'init'}{'geoipfree'} ) { $Message[17] = $Message[25] = $Message[148]; @@ -19248,7 +19250,10 @@ if ( $UpdateStats && $FrameName ne 'index' && $FrameName ne 'mainleft' ) $HostResolved = $Host; # Resolve Domain - if ( $PluginsLoaded{'GetCountryCodeByAddr'}{'geoip'} ) { + if ( $PluginsLoaded{'GetCountryCodeByAddr'}{'geoip6'} ) { + $Domain = GetCountryCodeByAddr_geoip6($HostResolved); + } + elsif ( $PluginsLoaded{'GetCountryCodeByAddr'}{'geoip'} ) { $Domain = GetCountryCodeByAddr_geoip($HostResolved); } @@ -19277,7 +19282,10 @@ if ( $UpdateStats && $FrameName ne 'index' && $FrameName ne 'mainleft' ) # Resolve Domain if ($ip) { # If we have ip, we use it in priority instead of hostname - if ( $PluginsLoaded{'GetCountryCodeByAddr'}{'geoip'} ) { + if ( $PluginsLoaded{'GetCountryCodeByAddr'}{'geoip6'} ) { + $Domain = GetCountryCodeByAddr_geoip6($Host); + } + elsif ( $PluginsLoaded{'GetCountryCodeByAddr'}{'geoip'} ) { $Domain = GetCountryCodeByAddr_geoip($Host); } @@ -19303,7 +19311,10 @@ if ( $UpdateStats && $FrameName ne 'index' && $FrameName ne 'mainleft' ) } } else { - if ( $PluginsLoaded{'GetCountryCodeByName'}{'geoip'} ) { + if ( $PluginsLoaded{'GetCountryCodeByName'}{'geoip6'} ) { + $Domain = GetCountryCodeByName_geoip6($HostResolved); + } + elsif ( $PluginsLoaded{'GetCountryCodeByName'}{'geoip'} ) { $Domain = GetCountryCodeByName_geoip($HostResolved); } diff --git a/wwwroot/cgi-bin/plugins/geoip6.pm b/wwwroot/cgi-bin/plugins/geoip6.pm new file mode 100644 index 00000000..399e5879 --- /dev/null +++ b/wwwroot/cgi-bin/plugins/geoip6.pm @@ -0,0 +1,270 @@ +#!/usr/bin/perl +# extended geoip.pm by Sven Strickroth +#----------------------------------------------------------------------------- +# GeoIP Maxmind AWStats plugin with IPv6 support +# This plugin allow you to get country report with countries detected +# from a Geographical database (GeoIP internal database) instead of domain +# hostname suffix. +# This works with IPv4 and also IPv6 +# Needs the IPv6 country database from Maxmind (free). +#----------------------------------------------------------------------------- +# Perl Required Modules: Geo::IP (Geo::IP::PurePerl does not support IPv6 yet) +#----------------------------------------------------------------------------- + +# <----- +# ENTER HERE THE USE COMMAND FOR ALL REQUIRED PERL MODULES +use vars qw/ $type /; +$type='geoip'; +if (!eval ('require "Geo/IP.pm";')) { + $error1=$@; +# $type='geoippureperl'; +# if (!eval ('require "Geo/IP/PurePerl.pm";')) { +# $error2=$@; +# $ret=($error1||$error2)?"Error:\n$error1$error2":""; + $ret.="Error: Need Perl module Geo::IP"; + return $ret; +# } +} else { + Geo::IP->VERSION >= 1.40 || die("Requires Geo/IP.pm >= 1.40"); +} +# -----> +#use strict; +no strict "refs"; + + + +#----------------------------------------------------------------------------- +# PLUGIN VARIABLES +#----------------------------------------------------------------------------- +# <----- +# ENTER HERE THE MINIMUM AWSTATS VERSION REQUIRED BY YOUR PLUGIN +# AND THE NAME OF ALL FUNCTIONS THE PLUGIN MANAGE. +my $PluginNeedAWStatsVersion="5.4"; +my $PluginHooksFunctions="GetCountryCodeByAddr GetCountryCodeByName ShowInfoHost"; +my $PluginName = "geoip6"; +my $LoadedOverride=0; +my $OverrideFile=""; +my %TmpDomainLookup; +# -----> + +# <----- +# IF YOUR PLUGIN NEED GLOBAL VARIABLES, THEY MUST BE DECLARED HERE. +use vars qw/ +$gi +/; +# -----> + + +#----------------------------------------------------------------------------- +# PLUGIN FUNCTION: Init_pluginname +#----------------------------------------------------------------------------- +sub Init_geoip6 { + my $InitParams=shift; + my $checkversion=&Check_Plugin_Version($PluginNeedAWStatsVersion); + + # <----- + # ENTER HERE CODE TO DO INIT PLUGIN ACTIONS + debug(" Plugin $PluginName: InitParams=$InitParams",1); + my ($mode,$tmpdatafile)=split(/\s+/,$InitParams,2); + my ($datafile,$override)=split(/\+/,$tmpdatafile,2); + if (! $datafile) { $datafile="$PluginName.dat"; } + else { $datafile =~ s/%20/ /g; } + if ($type eq 'geoippureperl') { + if ($mode eq '' || $mode eq 'GEOIP_MEMORY_CACHE') { $mode=Geo::IP::PurePerl::GEOIP_MEMORY_CACHE(); } + else { $mode=Geo::IP::PurePerl::GEOIP_STANDARD(); } + } else { + if ($mode eq '' || $mode eq 'GEOIP_MEMORY_CACHE') { $mode=Geo::IP::GEOIP_MEMORY_CACHE(); } + else { $mode=Geo::IP::GEOIP_STANDARD(); } + } + if ($override){$OverrideFile=$override;} + %TmpDomainLookup=(); + debug(" Plugin $PluginName: GeoIP initialized type=$type mode=$mode override=$override",1); + if ($type eq 'geoippureperl') { + $gi = Geo::IP::PurePerl->open($datafile, $mode); + } else { + $gi = Geo::IP->open($datafile, $mode); + } + +# Fails on some GeoIP version +# debug(" Plugin geoip6: GeoIP initialized database_info=".$gi->database_info()); + # -----> + + return ($checkversion?$checkversion:"$PluginHooksFunctions"); +} + + +#----------------------------------------------------------------------------- +# PLUGIN FUNCTION: GetCountryCodeByAddr_pluginname +# UNIQUE: YES (Only one plugin using this function can be loaded) +# GetCountryCodeByAddr is called to translate an ip into a country code in lower case. +#----------------------------------------------------------------------------- +sub GetCountryCodeByAddr_geoip6 { + my $param="$_[0]"; + # <----- + if (! $param) { return ''; } + my $searchkey; + if ($param =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) { # IPv4 address + $searchkey = '::'.$param; + } else { + $searchkey = $param; + } + my $res= TmpLookup_geoip6($param); + if (! $res) { + $res=lc($gi->country_code_by_addr_v6($searchkey)) || 'unknown'; + $TmpDomainLookup{$param}=$res; + if ($Debug) { debug(" Plugin $PluginName: GetCountryCodeByAddr for $searchkey: [$res]",5); } + } + elsif ($Debug) { debug(" Plugin $PluginName: GetCountryCodeByAddr for $param: Already resolved to [$res]",5); } + # -----> + return $res; +} + + +#----------------------------------------------------------------------------- +# PLUGIN FUNCTION: GetCountryCodeByName_pluginname +# UNIQUE: YES (Only one plugin using this function can be loaded) +# GetCountryCodeByName is called to translate a host name into a country code in lower case. +#----------------------------------------------------------------------------- +sub GetCountryCodeByName_geoip6 { + my $param="$_[0]"; + # <----- + if (! $param) { return ''; } + my $res = TmpLookup_geoip6($param); + if (! $res) { + $res=lc($gi->country_code_by_name_v6($param)) || 'unknown'; + $TmpDomainLookup{$param}=$res; + if ($Debug) { debug(" Plugin $PluginName: GetCountryCodeByName for $param: [$res]",5); } + } + elsif ($Debug) { debug(" Plugin $PluginName: GetCountryCodeByName for $param: Already resolved to [$res]",5); } + # -----> + return $res; +} + + +#----------------------------------------------------------------------------- +# PLUGIN FUNCTION: ShowInfoHost_pluginname +# UNIQUE: NO (Several plugins using this function can be loaded) +# Function called to add additionnal columns to the Hosts report. +# This function is called when building rows of the report (One call for each +# row). So it allows you to add a column in report, for example with code : +# print "This is a new cell for $param"; +# Parameters: Host name or ip +#----------------------------------------------------------------------------- +sub ShowInfoHost_geoip6 { + my $param="$_[0]"; + # <----- + if ($param eq '__title__') { + my $NewLinkParams=${QueryString}; + $NewLinkParams =~ s/(^|&)update(=\w*|$)//i; + $NewLinkParams =~ s/(^|&)output(=\w*|$)//i; + $NewLinkParams =~ s/(^|&)staticlinks(=\w*|$)//i; + $NewLinkParams =~ s/(^|&)framename=[^&]*//i; + my $NewLinkTarget=''; + if ($DetailedReportsOnNewWindows) { $NewLinkTarget=" target=\"awstatsbis\""; } + if (($FrameName eq 'mainleft' || $FrameName eq 'mainright') && $DetailedReportsOnNewWindows < 2) { + $NewLinkParams.="&framename=mainright"; + $NewLinkTarget=" target=\"mainright\""; + } + $NewLinkParams =~ tr/&/&/s; $NewLinkParams =~ s/^&//; $NewLinkParams =~ s/&$//; + if ($NewLinkParams) { $NewLinkParams="${NewLinkParams}&"; } + + print ""; + print "GeoIP
Country
"; + print ""; + } + elsif ($param) { + my $ip=0; + my $key; + if ($param =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) { # IPv4 address + $ip=4; + $key='::'.$param; + } + elsif ($param =~ /^[0-9A-F]*:/i) { # IPv6 address + $ip=6; + $key=$param; + } + print ""; + if ($key) { + my $res = TmpLookup_geoip6($param); + if (!$res && $gi) { + $res=lc($gi->country_code_by_addr_v6($key)); + } + if ($Debug) { debug(" Plugin $PluginName: GetCountryByIp for $key: [$res]",5); } + if ($res) { print $DomainsHashIDLib{$res}?$DomainsHashIDLib{$res}:"$Message[0]"; } + else { print "$Message[0]"; } + } + else { + my $res = TmpLookup_geoip6($param); + if (!$res){$res=lc($gi->country_code_by_name_v6($param)) if $gi;} + if ($Debug) { debug(" Plugin $PluginName: GetCountryByHostname for $param: [$res]",5); } + if ($res) { print $DomainsHashIDLib{$res}?$DomainsHashIDLib{$res}:"$Message[0]"; } + else { print "$Message[0]"; } + } + print ""; + } + else { + print " "; + } + return 1; + # -----> +} + +#----------------------------------------------------------------------------- +# PLUGIN FUNCTION: LoadOverrideFile +# Attempts to load a comma delimited file that will override the GeoIP database +# Useful for Intranet records +# CSV format: IP,2-char Country code +#----------------------------------------------------------------------------- +sub LoadOverrideFile_geoip6{ + my $filetoload=""; + if ($OverrideFile){ + if (!open(GEOIPFILE, $OverrideFile)){ + debug("Plugin $PluginName: Unable to open override file: $OverrideFile"); + $LoadedOverride = 1; + return; + } + }else{ + my $conf = (exists(&Get_Config_Name) ? Get_Config_Name() : $SiteConfig); + if ($conf && open(GEOIPFILE,"$DirData/$PluginName.$conf.txt")) { $filetoload="$DirData/$PluginName.$conf.txt"; } + elsif (open(GEOIPFILE,"$DirData/$PluginName.txt")) { $filetoload="$DirData/$PluginName.txt"; } + else { debug("No override file \"$DirData/$PluginName.txt\": $!"); } + } + if ($filetoload) + { + # This is the fastest way to load with regexp that I know + while (){ + chomp $_; + s/\r//; + my @record = split(",", $_); + # replace quotes if they were used in the file + foreach (@record){ $_ =~ s/"//g; } + # store in hash + $TmpDomainLookup{$record[0]} = $record[1]; + } + close GEOIPFILE; + debug(" Plugin $PluginName: Overload file loaded: ".(scalar keys %TmpDomainLookup)." entries found."); + } + $LoadedOverride = 1; + return; +} + +#----------------------------------------------------------------------------- +# PLUGIN FUNCTION: TmpLookup +# Searches the temporary hash for the parameter value and returns the corresponding +# GEOIP entry +#----------------------------------------------------------------------------- +sub TmpLookup_geoip6(){ + $param = shift; + if (!$LoadedOverride){&LoadOverrideFile_geoip6();} + #my $val; + #if ($gi && + #(($type eq 'geoip' && $gi->VERSION >= 1.30) || + # $type eq 'geoippureperl' && $gi->VERSION >= 1.17)){ + # $val = $TmpDomainLookup{$gi->get_ip_address($param)}; + #} + #else {$val = $TmpDomainLookup{$param};} + #return $val || ''; + return $TmpDomainLookup{$param}||''; +} + +1; # Do not remove this line