filter_innd.pl wird im Kontext des inn-Daemons ausgeführt. Im Gegen-
satz zu filter_nnrpd.pl bekommt also nicht jeder Client eine eigene,
frische Instanz. Um Änderungen an filter_innd.pl wirksam zu machen,
bedarf es
ctlinnd reload filter.perl "hier noch eine begründung"
Kommt es zu Syntax-Fehlern beim Laden bzw. fatalen Fehler bei der
Ausführung ("die") wird das Perl-Filtering dauerhaft abgestellt.
In diesem Fall bedarf es dann eines Neustarts von inn.
Es empfiehlt sich daher, Änderungen vor dem "reload" mit
perl -wc filter_nnrpd.pl
zumindest oberflächlich prüfen zu lassen.
Üblicherweise ist filter_innd.pl ein Symbolic Link auf die Datei
"cleanfeed" welche ihrerseits "cleanfeed.local" lädt. Wenn die
Funktion "local_filter_cancel" existiert, wird sie von "cleanfeed"
für Cancel-Postings (nach erfolgreichen bestehen aller anderen
Cancel-Prüfungen) ausgeführt.
sub local_filter_cancel
{
unless($hdr{Control} =~ m/^cancel\s+(<[^>]+>)/i)
{ return "Cancel with broken target ID"; }
my $target = $1;
my $headers = INN::head($target) ||
return "Cancel of non-existing ID $target";
my %headers;
for my $line(split(/\s*\n/, $headers))
{
if ($line =~ m/^([[:alnum:]-]+):\s+(.*)/)
{ $headers{$1} = $2; }
}
my $lock = $headers{'Cancel-Lock'};
if (defined($lock))
{
my $key = $hdr{'Cancel-Key'} ||
return "Cancel of $target without Cancel-Key";
my $rc = verify_cancel_key($key, $lock);
return $rc . ' target=' . $target if (defined($rc));
}
# else { return "Cancel of $target without Cancel-Lock"; }
return undef;
}
Die von INN bereitgestelle Funktion "INN::head" lädt ein
Posting aus dem Newsspool und gibt dessen Header in Form
einer Zeichenkette zurück.
Diese Implementierung kümmert sich nur um Ziel-Postings,
die ein Feld "Cancel-Lock:" aufweisen. Entfernt man das
"#" vor dem "else" werden alle Ziel-Postings ohne Cancel-
Lock nicht mehr cancelbar.
sub verify_cancel_key($$)
{
my $cancel_key = shift;
my $cancel_lock = shift;
my %lock;
for my $l(split(/\s+/, $cancel_lock))
{
next unless($l =~ m/^(sha1|md5):(\S+)/);
$lock{$2} = 1;
}
for my $k(split(/\s+/, $cancel_key))
{
next unless($k =~ m/^(sha1|md5):(\S+)/);
my $key;
if ($1 eq 'sha1')
{ $key = Digest::SHA1::sha1($2); }
elsif ($1 eq 'md5')
{ $key = Digest::MD5::md5($2); }
else
{
INN::syslog('notice', "Invalid cancel-key schema $1.");
next;
}
$key = MIME::Base64::encode_base64($key);
if (exists($lock{$key}))
{
INN::syslog('notice', "Valid cancel key $key found.");
return undef;
}
}
INN::syslog('notice', "No Cancel-Key[$cancel_key] matches Cancel-Lock[$cancel_lock]");
return "No Cancel-Key matches Cancel-Lock.";
}
Diese Funktion kann mit mehreren Locks und Keys umgehen. Die von INN
bereitgestellte Funktion "INN::syslog" wird für die Ausgabe weiter-
gehender Diagnose benutzt.
Auf einen Vergleich der Schema-Felder in Key und Lock habe ich
verzichtet.
filter_innd.pl wird im Kontext des inn-Daemons ausgeführt. Im Gegen-
satz zu filter_nnrpd.pl bekommt also nicht jeder Client eine eigene,
frische Instanz. Um Änderungen an filter_innd.pl wirksam zu machen,
bedarf es
ctlinnd reload filter.perl "hier noch eine begründung"
Kommt es zu Syntax-Fehlern beim Laden bzw. fatalen Fehler bei der
Ausführung ("die") wird das Perl-Filtering dauerhaft abgestellt.
In diesem Fall bedarf es dann eines Neustarts von inn.
Es empfiehlt sich daher, Änderungen vor dem "reload" mit
perl -wc filter_nnrpd.pl
zumindest oberflächlich prüfen zu lassen.
Üblicherweise ist filter_innd.pl ein Symbolic Link auf die Datei
"cleanfeed" welche ihrerseits "cleanfeed.local" lädt. Wenn die
Funktion "local_filter_cancel" existiert, wird sie von "cleanfeed"
für Cancel-Postings (nach erfolgreichen bestehen aller anderen
Cancel-Prüfungen) ausgeführt.
use Digest::SHA1();
use Digest::MD5();
use MIME::Base64();
> Das folgende ist eine Proof-Of-Concept-Implementierung um unter
> INN mit Cleanfeed alle eingehenden Cancel-Postings zu prüfen.
Ich habe letzten Freitag das Perl-Modul News::Article um
Cancellock-Fähigkeiten erweitert, hier gibt's ein Diff zur Version 1.27:
http://www.trash.net/~roman/weiteres/Article.pm.diff
Gruss
Roman°
--
IRC-Freenode: #usenet-friends
http://www.usenet-friends.ch.vu/
Der Code im Vorposting ist buggy, äh, sub-optimal.
Folgende Version ist jetzt auf news.albasani.net im Einsatz:
use Digest::SHA1();
use Digest::MD5();
use MIME::Base64();
sub verify_cancel_key($$)
{
my $cancel_key = shift;
my $cancel_lock = shift;
my %lock;
for my $l(split(/\s+/, $cancel_lock))
{
next unless($l =~ m/^(sha1|md5):(\S+)/);
$lock{$2} = $1;
}
for my $k(split(/\s+/, $cancel_key))
{
unless($k =~ m/^(sha1|md5):(\S+)/)
{
INN::syslog('notice', "Invalid cancel-key syntax $k");
next;
}
my $key;
if ($1 eq 'sha1')
{ $key = Digest::SHA1::sha1($2); }
else ($1 eq 'md5')
{ $key = Digest::MD5::md5($2); }
$key = MIME::Base64::encode_base64($key, '');
if (exists($lock{$key}))
{
INN::syslog('notice', "Valid cancel key $key found.");
return undef;
}
}
INN::syslog('notice',
"No Cancel-Key[$cancel_key] matches Cancel-Lock[$cancel_lock]"
);
return "No Cancel-Key matches Cancel-Lock.";
}
sub local_filter_cancel
{
unless($hdr{Control} =~ m/^cancel\s+(<[^>]+>)/i)
{ return "Cancel with broken target ID"; }
my $target = $1;
my $headers = INN::head($target) ||
return "Cancel of non-existing ID $target";
my %headers;
for my $line(split(/\s*\n/, $headers))
{
if ($line =~ m/^([[:alnum:]-]+):\s+(.*)/)
{ $headers{$1} = $2; }
}
my $lock = $headers{'Cancel-Lock'};
if (defined($lock))
{
my $key = $hdr{'Cancel-Key'} ||
return "Cancel of $target without Cancel-Key";
my $rc = verify_cancel_key($key, $lock);
return $rc . ' target=' . $target if (defined($rc));
}
return undef;
}
--
Der Code im Vorposting ist buggy, äh, sub-optimal.
Folgende Version ist jetzt auf news.albasani.net im Einsatz:
use Digest::SHA1();
use Digest::MD5();
use MIME::Base64();
sub verify_cancel_key($$)
{
my $cancel_key = shift;
my $cancel_lock = shift;
my %lock;
for my $l(split(/\s+/, $cancel_lock))
{
next unless($l =~ m/^(sha1|md5):(\S+)/);
$lock{$2} = $1;
}
for my $k(split(/\s+/, $cancel_key))
{
unless($k =~ m/^(sha1|md5):(\S+)/)
{
INN::syslog('notice', "Invalid cancel-key syntax $k");
next;
}
my $key;
if ($1 eq 'sha1')
{ $key = Digest::SHA1::sha1($2); }
elsif ($1 eq 'md5')
{ $key = Digest::MD5::md5($2); }
$key = MIME::Base64::encode_base64($key, '');
if (exists($lock{$key}))
{
INN::syslog('notice', "Valid cancel key $key found.");
return undef;
}
}
INN::syslog('notice',
"No Cancel-Key[$cancel_key] matches Cancel-Lock[$cancel_lock]"
);
return "No Cancel-Key matches Cancel-Lock.";
}
sub local_filter_cancel
{
unless($hdr{Control} =~ m/^cancel\s+(<[^>]+>)/i)
{ return "Cancel with broken target ID"; }
my $target = $1;
my $headers = INN::head($target) ||
return "Cancel of non-existing ID $target";
my %headers;
for my $line(split(/\s*\n/, $headers))
{
if ($line =~ m/^([[:alnum:]-]+):\s+(.*)/)
{ $headers{$1} = $2; }
}
my $lock = $headers{'Cancel-Lock'};
if (defined($lock))
{
my $key = $hdr{'Cancel-Key'} ||
return "Cancel of $target without Cancel-Key";
my $rc = verify_cancel_key($key, $lock);
return $rc . ' target=' . $target if (defined($rc));
}
return undef;
}
--
> Der Code im Vorposting ist buggy, äh, sub-optimal.
> Folgende Version ist jetzt auf news.albasani.net im Einsatz:
Und so klappt's auch mit den Supersedes:
sub local_filter_after_emp {
if ( $hdr{Supersedes} ) {
unless($hdr{Supersedes} =~ m/^(<[^>]+>)/)
{ return "Supersedes with broken target ID"; }
my $target = $1;
my $headers = INN::head($target) ||
return "Supersedes of non-existing ID $target";
my %headers;
for my $line(split(/\s*\n/, $headers))
{
if ($line =~ m/^([[:alnum:]-]+):\s+(.*)/)
{ $headers{$1} = $2; }
}
my $lock = $headers{'Cancel-Lock'};
if (defined($lock))
{
my $key = $hdr{'Cancel-Key'} ||
return "Supersedes of $target without Cancel-Key";
my $rc = verify_cancel_key($key, $lock);
return $rc . ' target=' . $target if (defined($rc));
}
}
return undef;
}
--
Too many ingredients in the soup, no room for a spoon.
http://news.motzarella.org