diff --git a/doc/pod/innd.pod b/doc/pod/innd.pod index 6e16e5160..2f2390dc8 100644 --- a/doc/pod/innd.pod +++ b/doc/pod/innd.pod @@ -496,15 +496,6 @@ SIGINT will also be caught and will result in an orderly shutdown. B will catch the SIGUSR1 signal and recreate the control channel used by ctlinnd(8). -=head1 BUGS - -B normally attempts to strip IP options from incoming connections, -since it uses IP-based authentication and source routing can confuse that. -However, this doesn't work on all systems, and it doesn't work at all in -the presence of IPv6 support (and is disabled in that case). Hence, if -using B with IPv6 support, make sure that your kernel or router -disables source routing. - =head1 HISTORY Written by Rich $alz for InterNetNews. diff --git a/doc/pod/news.pod b/doc/pod/news.pod index ea08db2db..7a6848bc6 100644 --- a/doc/pod/news.pod +++ b/doc/pod/news.pod @@ -23,6 +23,20 @@ C<:bytes> and C<:lines> metadata to news clients using CAPABILITIES. =back +=head1 Changes in 2.7.3 (not yet released) + +=over 2 + +=item * + +Several improvements have been made to readership statistics reported by +B: IPv6 addresses are now correctly recognized and reported +as unresolved instead of unknown, statistics by domain are at a better +granularity, totals are correctly computed, and only the top 100 entries are +displayed by default instead of a possibly very long exhaustive list. + +=back + =head1 Changes in 2.7.2 (2024-06-22) =over 2 diff --git a/scripts/innreport-display.conf b/scripts/innreport-display.conf index 53e6f8637..1f567b832 100644 --- a/scripts/innreport-display.conf +++ b/scripts/innreport-display.conf @@ -2150,6 +2150,7 @@ section rnews_misc { section nnrpd_groups { title "NNRP readership statistics:"; data "%nnrpd_connect"; + top 100; sort "$nnrpd_articles{$b} <=> $nnrpd_articles{$a} or $nnrpd_connect{$b} <=> $nnrpd_connect{$a} or $a cmp $b"; @@ -2212,8 +2213,9 @@ section nnrpd_groups { }; section nnrpd_dom_groups { - title "NNRP readership statistics (by domain):"; + title "NNRP connection statistics (by domain):"; data "%nnrpd_dom_connect"; + top 100; sort "$nnrpd_dom_articles{$b} <=> $nnrpd_dom_articles{$a} or $nnrpd_dom_connect{$b} <=> $nnrpd_dom_connect{$a} or $a cmp $b"; @@ -2341,7 +2343,7 @@ section nnrpd_resource { }; section nnrpd_curious { - title "Curious NNRP server explorers:"; + title "Curious NNRP explorers:"; data "%nnrpd_curious"; top 20; sort "$nnrpd_curious{$b} <=> $nnrpd_curious{$a} or $a cmp $b"; @@ -2480,6 +2482,7 @@ section nnrpd_timeout { section nnrpd_hierarchy { title "Newsgroup request counts (by hierarchy):"; data "%nnrpd_hierarchy"; + top 100; sort "$nnrpd_hierarchy{$b} <=> $nnrpd_hierarchy{$a} or $a cmp $b"; numbering true; column { @@ -2509,8 +2512,8 @@ section nnrpd_hierarchy { section nnrpd_group { title "Newsgroup request counts (by newsgroup):"; data "%nnrpd_group"; - sort "$nnrpd_group{$b} <=> $nnrpd_group{$a} or $a cmp $b"; top 100; + sort "$nnrpd_group{$b} <=> $nnrpd_group{$a} or $a cmp $b"; numbering true; column { name "Newsgroup"; diff --git a/scripts/innreport_inn.pm b/scripts/innreport_inn.pm index 981c56a7d..ccea3be69 100644 --- a/scripts/innreport_inn.pm +++ b/scripts/innreport_inn.pm @@ -260,7 +260,6 @@ our %nnrpd_resource_elapsed; our %nnrpd_resource_idle; our %nnrpd_resource_system; our %nnrpd_resource_user; -our %nnrpd_sys_times; our %nnrpd_time_max; our %nnrpd_time_min; our %nnrpd_time_num; @@ -270,7 +269,6 @@ our %nnrpd_time_time; our $nnrpd_time_times; our %nnrpd_unrecogn_cmd; our %nnrpd_unrecognized; -our %nnrpd_usr_times; our %nntplink_accepted; our %nntplink_auth; our %nntplink_bpipe; @@ -2377,58 +2375,105 @@ sub collect($$$$$$) { sub adjust($$) { my ($first_date, $last_date) = @_; - my $nnrpd_doit = 0; - my $curious; + if (%nnrpd_connect) { + my @keys = keys(%nnrpd_connect); + my $c = @keys; + foreach my $serv (@keys) { + my $dom = &host2dom($serv); + + # Mark connections without any actual reader action as curious. + if (%nnrpd_groups) { + unless ($nnrpd_groups{$serv} + || $nnrpd_post_ok{$serv} + || $nnrpd_post_rej{$serv} + || $nnrpd_post_error{$serv} + || $nnrpd_articles{$serv}) + { + $nnrpd_curious{$serv} = $nnrpd_connect{$serv}; + } + } - { - if (%nnrpd_connect) { - my @keys = keys(%nnrpd_connect); - my $c = @keys; - foreach my $serv (@keys) { - if ($nnrpd_no_permission{$serv}) { - my $dom = &host2dom($serv); - $nnrpd_dom_connect{$dom} -= $nnrpd_connect{$serv} - if defined $nnrpd_dom_connect{$dom}; - $nnrpd_dom_times{$dom} -= $nnrpd_times{$serv} - if defined $nnrpd_dom_times{$dom}; - - # The message "bad_auth" can occur more than once per - # session. Subtracting nnrpd_no_permission from - # nnrpd_connect is broken and can yield negative values - # for nnrpd_connect. - $nnrpd_connect{$serv} -= $nnrpd_no_permission{$serv}; - - # Perl considers negative values to be true. Previously - # the hash entry was deleted only if the value was - # exactly 0. - delete $nnrpd_connect{$serv} - unless $nnrpd_connect{$serv} > 0; - - delete $nnrpd_groups{$serv} unless $nnrpd_groups{$serv}; - delete $nnrpd_times{$serv} unless $nnrpd_times{$serv}; - delete $nnrpd_usr_times{$serv} - unless $nnrpd_usr_times{$serv}; - delete $nnrpd_sys_times{$serv} - unless $nnrpd_sys_times{$serv}; - delete $nnrpd_dom_connect{$dom} - unless $nnrpd_dom_connect{$dom} > 0; - delete $nnrpd_dom_groups{$dom} - unless $nnrpd_dom_groups{$dom}; - delete $nnrpd_dom_times{$dom} - unless $nnrpd_dom_times{$dom}; - $c--; + # After the check for curious readers, as the number of + # connections is modified. + if ($nnrpd_no_permission{$serv}) { + # The message "bad_auth" can occur more than once per + # session. Subtracting nnrpd_no_permission from + # nnrpd_connect is broken and can yield negative values + # for nnrpd_connect. + $nnrpd_connect{$serv} -= $nnrpd_no_permission{$serv}; + $nnrpd_dom_connect{$dom} -= $nnrpd_no_permission{$serv} + if (exists($nnrpd_dom_connect{$dom})); + } + + # Perl considers negative values to be true. Previously + # the hash entry was deleted only if the value was + # exactly 0. + if ($nnrpd_connect{$serv} <= 0 + or exists($nnrpd_curious{$serv})) + { + if (exists($nnrpd_dom_connect{$dom})) { + if ($nnrpd_dom_connect{$dom} <= 0) { + delete($nnrpd_dom_connect{$dom}); + delete($nnrpd_dom_articles{$dom}) + if (exists($nnrpd_dom_articles{$dom})); + delete($nnrpd_dom_bytes{$dom}) + if (exists($nnrpd_dom_bytes{$dom})); + delete($nnrpd_dom_groups{$dom}) + if (exists($nnrpd_dom_groups{$dom})); + delete($nnrpd_dom_post_error{$dom}) + if (exists($nnrpd_dom_post_error{$dom})); + delete($nnrpd_dom_post_ok{$dom}) + if (exists($nnrpd_dom_post_ok{$dom})); + delete($nnrpd_dom_post_rej{$dom}) + if (exists($nnrpd_dom_post_rej{$dom})); + delete($nnrpd_dom_times{$dom}) + if (exists($nnrpd_dom_times{$dom})); + } elsif (!exists($nnrpd_curious{$serv})) { + $nnrpd_dom_articles{$dom} -= $nnrpd_articles{$serv} + if (exists($nnrpd_dom_articles{$dom}) + and exists($nnrpd_articles{$serv})); + $nnrpd_dom_bytes{$dom} -= $nnrpd_bytes{$serv} + if (exists($nnrpd_dom_bytes{$dom}) + and exists($nnrpd_bytes{$serv})); + $nnrpd_dom_groups{$dom} -= $nnrpd_groups{$serv} + if (exists($nnrpd_dom_groups{$dom}) + and exists($nnrpd_groups{$serv})); + $nnrpd_dom_post_error{$dom} -= $nnrpd_post_error{$serv} + if (exists($nnrpd_dom_post_error{$dom}) + and exists($nnrpd_post_error{$serv})); + $nnrpd_dom_post_ok{$dom} -= $nnrpd_post_ok{$serv} + if (exists($nnrpd_dom_post_ok{$dom}) + and exists($nnrpd_post_ok{$serv})); + $nnrpd_dom_post_rej{$dom} -= $nnrpd_post_rej{$serv} + if (exists($nnrpd_dom_post_rej{$dom}) + and exists($nnrpd_post_rej{$serv})); + $nnrpd_dom_times{$dom} -= $nnrpd_times{$serv} + if (exists($nnrpd_dom_times{$dom}) + and exists($nnrpd_times{$serv})); + } } - $nnrpd_doit++ - if $nnrpd_groups{$serv} || $nnrpd_post_ok{$serv}; + + # Do not report the connections. + delete($nnrpd_connect{$serv}); + delete($nnrpd_articles{$serv}) + if (exists($nnrpd_articles{$serv})); + delete($nnrpd_bytes{$serv}) + if (exists($nnrpd_bytes{$serv})); + delete($nnrpd_groups{$serv}) + if (exists($nnrpd_groups{$serv})); + delete($nnrpd_post_error{$serv}) + if (exists($nnrpd_post_error{$serv})); + delete($nnrpd_post_ok{$serv}) + if (exists($nnrpd_post_ok{$serv})); + delete($nnrpd_post_rej{$serv}) + if (exists($nnrpd_post_rej{$serv})); + delete($nnrpd_times{$serv}) + if (exists($nnrpd_times{$serv})); + + $c--; } - undef %nnrpd_connect unless $c; - } - foreach my $serv (keys(%nnrpd_groups)) { - $curious = "ok" - unless $nnrpd_groups{$serv} - || $nnrpd_post_ok{$serv} - || $nnrpd_articles{$serv}; } + undef(%nnrpd_connect) unless ($c); } # Fill some hashes @@ -2697,19 +2742,6 @@ sub adjust($$) { $rnews_misc{'No colon-space'}{'--'} = $rnews_no_colon_space if $rnews_no_colon_space; - if (%nnrpd_groups) { - foreach my $key (keys(%nnrpd_connect)) { - unless ($nnrpd_groups{$key} - || $nnrpd_post_ok{$key} - || $nnrpd_post_rej{$key} - || $nnrpd_post_error{$key} - || $nnrpd_articles{$key}) - { - $nnrpd_curious{$key} = $nnrpd_connect{$key}; - delete $nnrpd_connect{$key}; - } - } - } } sub report_unwanted_ng($) { @@ -2767,8 +2799,19 @@ sub datecmp() { sub host2dom($) { my $host = shift; - $host =~ m/^[^\.]+(.*)/; - $host =~ m/^[\d\.]+$/ ? "unresolved" : $1 ? "*$1" : "?"; + # Unresolved IPv4 and IPv6 addresses. + return "unresolved" if ($host =~ /^[\d\.]+$/); + return "unresolved" if ($host =~ /^[\da-fA-F\:]+$/); + + # Keep up to the last 3 components of the hostname. + # (Some country code top-level domains have 2 components, like ".co.uk".) + $host =~ m/((?:\.[^\.]+){1,3})$/; + + if ($1) { + return "*$1"; + } else { + return "?"; + } } 1;