X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=blobdiff_plain;ds=sidebyside;f=doc%2Fpod%2Fhook-perl.pod;fp=doc%2Fpod%2Fhook-perl.pod;h=0000000000000000000000000000000000000000;hb=b7a32e2d73e3ab1add8208d3e157f7269a31ef4d;hp=a860393e560f9d72ab8e7250b21a2b6a4cc6eb87;hpb=ac902a8299ff4469b356836f431ead31c3377377;p=innduct.git diff --git a/doc/pod/hook-perl.pod b/doc/pod/hook-perl.pod deleted file mode 100644 index a860393..0000000 --- a/doc/pod/hook-perl.pod +++ /dev/null @@ -1,614 +0,0 @@ -=head1 INN Perl Filtering and Authentication Support - -This is $Revision: 7860 $ dated $Date: 2008-06-07 05:46:49 -0700 (Sat, 07 Jun 2008) $. - -This file documents INN's built-in support for Perl filtering and reader -authentication. The code is based very heavily on work by Christophe -Wolfhugel , and his work was in turn inspired by the -existing TCL support. Please send any bug reports to inn-bugs@isc.org, -not to Christophe, as the code has been modified heavily since he -originally wrote it. - -The Perl filtering support is described in more detail below. Basically, -it allows you to supply a Perl function that is invoked on every article -received by innd from a peer (the innd filter) or by nnrpd from a reader -(the nnrpd filter). This function can decide whether to accept or reject -the article, and can optionally do other, more complicated processing -(such as add history entries, cancel articles, spool local posts into a -holding area, or even modify the headers of locally submitted posts). -The Perl authentication hooks allow you to replace or supplement the -readers.conf mechanism used by nnrpd. - -For Perl filtering support, you need to have Perl version 5.004 or newer. -Earlier versions of Perl will fail with a link error at compilation time. -http://language.perl.com/info/software.html should have the latest Perl -version. - -To enable Perl support, you have to specify B<--with-perl> when you run -configure. See F for more information. - -=head1 The innd Perl Filter - -When innd starts, it first loads the file _PATH_PERL_STARTUP_INND (defined -in F, by default F) and then loads the -file _PATH_PERL_FILTER_INND (also defined in F, by -default F). Both of these files must be located in the -directory specified by pathfilter in F -(F by default). The default directory for -filter code can be specified at configure time by giving the flag -B<--with-filter-dir> to configure. - -INN doesn't care what Perl functions you define in which files. The only -thing that's different about the two files is when they're loaded. -F is loaded only once, when innd first starts, and is -never reloaded as long as innd is running. Any modifications to that file -won't be noticed by innd; only stopping and restarting innd can cause it -to be reloaded. - -F, on the other hand, can be reloaded on command (with -C). Whenever F is loaded, -including the first time at innd startup, the Perl function -filter_before_reload() is called before it's reloaded and the function -filter_after_reload() is called after it's reloaded (if the functions -exist). Additionally, any code in either F or -F at the top level (in other words, not inside a sub { }) -is automatically executed by Perl when the files are loaded. - -This allows one to do things like write out filter statistics whenever the -filter is reloaded, load a cache into memory, flush cached data to disk, -or other similar operations that should only happen at particular times or -with manual intervention. Remember, any code not inside functions in -F is executed when that file is loaded, and it's loaded -only once when innd first starts. That makes it the ideal place to put -initialization code that should only run once, or code to load data that -was preserved on disk across a stop and restart of innd (perhaps using -filter_mode() -- see below). - -As mentioned above, C (or C) will cause F to be reloaded. If the function -filter_art() is defined after the file has been reloaded, filtering is -turned on. Otherwise, filtering is turned off. (Note that due to the way -Perl stores functions, once you've defined filter_art(), you can't -undefine it just by deleting it from the file and reloading the filter. -You'll need to replace it with an empty sub.) - -The Perl function filter_art() is the heart of a Perl filter. Whenever an -article is received from a peer, via either IHAVE or TAKETHIS, -filter_art() is called if Perl filtering is turned on. It receives no -arguments, and should return a single scalar value. That value should be -the empty string to indicate that INN should accept the article, or some -rejection message to indicate that the article should be rejected. - -filter_art() has access to a global hash named %hdr, which contains all of -the standard headers present in the article and their values. The -standard headers are: - - Also-Control, Approved, Bytes, Cancel-Key, Cancel-Lock, - Content-Base, Content-Disposition, Content-Transfer-Encoding, - Content-Type, Control, Date, Date-Received, Distribution, Expires, - Face, Followup-To, From, In-Reply-To, Injection-Date, Injection-Info, - Keywords, Lines, List-ID, Message-ID, MIME-Version, Newsgroups, - NNTP-Posting-Date, NNTP-Posting-Host, Organization, Originator, - Path, Posted, Posting-Version, Received, References, Relay-Version, - Reply-To, Sender, Subject, Supersedes, User-Agent, - X-Auth, X-Canceled-By, X-Cancelled-By, X-Complaints-To, X-Face, - X-HTTP-UserAgent, X-HTTP-Via, X-Mailer, X-Modbot, X-Modtrace, - X-Newsposter, X-Newsreader, X-No-Archive, X-Original-Message-ID, - X-Original-Trace, X-Originating-IP, X-PGP-Key, X-PGP-Sig, - X-Poster-Trace, X-Postfilter, X-Proxy-User, X-Submissions-To, - X-Trace, X-Usenet-Provider, Xref. - -Note that all the above headers are as they arrived, not modified by -your INN (especially, the Xref: header, if present, is the one of -the remote site which sent you the article, and not yours). - -For example, the Newsgroups: header of the article is accessible -inside the Perl filter as C<$hdr{'Newsgroups'}>. In addition, -C<$hdr{'__BODY__'}> will contain the full body of the article and -C<$hdr{'__LINES__'}> will contain the number of lines in the body of the -article. - -The contents of the %hdr hash for a typical article may therefore look -something like this: - - %hdr = (Subject => 'MAKE MONEY FAST!!', - From => 'Joe Spamer ', - Date => '10 Sep 1996 15:32:28 UTC', - Newsgroups => 'alt.test', - Path => 'news.example.com!not-for-mail', - Organization => 'Spammers Anonymous', - Lines => '5', - Distribution => 'usa', - 'Message-ID' => '<6.20232.842369548@example.com>', - __BODY__ => 'Send five dollars to the ISC, c/o ...', - __LINES__ => 5 - ); - -Note that the value of C<$hdr{Lines}> is the contents of the Lines: header -of the article and may bear no resemblence to the actual length of the -article. C<$hdr{__LINES__}> is the line count calculated by INN, and is -guaranteed to be accurate. - -The %hdr hash should not be modified inside filter_art(). Instead, if any -of the contents need to be modified temporarily during filtering (smashing -case, for example), copy them into a seperate variable first and perform -the modifications on the copy. Currently, C<$hdr{__BODY__}> is the only -data that will cause your filter to die if you modify it, but in the -future other keys may also contain live data. Modifying live INN data in -Perl will hopefully only cause a fatal exception in your Perl code that -disables Perl filtering until you fix it, but it's possible for it to -cause article munging or even core dumps in INN. So always, always make a -copy first. - -As mentioned above, if filter_art() returns the empty string (''), the -article is accepted. Note that this must be the empty string, not 0 or -undef. Otherwise, the article is rejected, and whatever scalar -filter_art() returns (typically a string) will be taken as the reason why -the article was rejected. This reason will be returned to the remote peer -as well as logged to the news logs. (innreport, in its nightly report, -will summarize the number of articles rejected by the Perl filter and -include a count of how many articles were rejected with each reason -string.) - -One other type of filtering is also supported. If Perl filtering is -turned on and the Perl function filter_messageid() is defined, that -function will be called for each message ID received from a peer (via -either CHECK or IHAVE). The function receives a single argument, the -message ID, and like filter_art() should return an empty string to accept -the article or an error string to refuse the article. This function is -called before any history lookups and for every article offered to innd -with CHECK or IHAVE (before the actual article is sent). Accordingly, the -message ID is the only information it has about the article (the %hdr hash -will be empty). This code would sit in a performance-critical hot path in -a typical server, and therefore should be as fast as possible, but it can -do things like refuse articles from certain hosts or cancels for already -rejected articles (if they follow the $alz convention) without having to -take the network bandwidth hit of accepting the entire article first. - -Note that you cannot rely on filter_messageid() being called for every -incoming article; articles sent via TAKETHIS without an earlier CHECK will -never pass through filter_messageid() and will only go through -filter_art(). - -Finally, whenever ctlinnd throttle, ctlinnd pause, or ctlinnd go is run, -the Perl function filter_mode() is called if it exists. It receives no -arguments and returns no value, but it has access to a global hash %mode -that contains three values: - - Mode The current server mode (throttled, paused, or running) - NewMode The new mode the server is going to - reason The reason that was given to ctlinnd - -One possible use for this function is to save filter state across a -restart of innd. There isn't any Perl function which is called when INN -shuts down, but using filter_mode() the Perl filter can dump it's state to -disk whenever INN is throttled. Then, if the news administrator follows -the strongly recommended shutdown procedure of throttling the server -before shutting it down, the filter state will be safely saved to disk and -can be reloaded when innd restarts (possibly by F). - -The state of the Perl interpretor in which all of these Perl functions run -is preserved over the lifetime of innd. In other words, it's permissible for -the Perl code to create its own global Perl variables, data structures, -saved state, and the like, and all of that will be available to -filter_art() and filter_messageid() each time they're called. The only -variable INN fiddles with (or pays any attention to at all) is %hdr, which -is cleared after each call to filter_art(). - -Perl filtering can be turned off with C and back on again -with C. Perl filtering is turned off automatically if -loading of the filter fails or if the filter code returns any sort of a -fatal error (either due to Perl itself or due to a C in the Perl code). - -=head1 Supported innd Callbacks - -innd makes seven functions available to any of its embedded Perl code. -Those are: - -=over 4 - -=item INN::addhist(I, I, I, I, I) - -Adds I to the history database. All of the arguments except -the first one are optional; the times default to the current time and the -paths field defaults to the empty string. (For those unfamiliar with the -fields of a history(5) database entry, the I is normally the time at -which the server accepts the article, the I is from the Date -header of the article, the I is from the Expires header of the -article, and the I field is the storage API token. All three times -as measured as a time_t since the epoch.) Returns true on success, false -otherwise. - -=item INN::article(I) - -Returns the full article (as a simple string) identified by I, -or undef if it isn't found. Each line will end with a simple \n, but -leading periods may still be doubled if the article is stored in wire -format. - -=item INN::cancel(I) - -Cancels I. (This is equivalent to C; it -cancels the message on the local server, but doesn't post a cancel message -or do anything else that affects anything other than the local server.) -Returns true on success, false otherwise. - -=item INN::filesfor(I) - -Returns the I field of the history entry for the given -I. This will be the storage API token for the message. If -I isn't found in the history database, returns undef. - -=item INN::havehist(I) - -Looks up I in the history database and returns true if it's -found, false otherwise. - -=item INN::head(I) - -Returns the header (as a simple string) of the article identified by -I, or undef if it isn't found. Each line will end with a -simple \n (in other words, regardless of the format of article storage, -the returned string won't be in wire format). - -=item INN::newsgroup(I) - -Returns the status of I (the last field of the active file -entry for that newsgroup). See active(5) for a description of the -possible values and their meanings (the most common are "y" for an -unmoderated group and "m" for a moderated group). If I isn't -in the active file, returns undef. - -=back - -These functions can only be used from inside the innd Perl filter; they're -not available in the nnrpd filter. - -=head1 Common Callbacks - -The following additional function is available from inside filters -embedded in innd, and is also available from filters embedded in nnrpd -(see below): - -=over 4 - -=item INN::syslog(level, message) - -Logs a message via syslog(2). This is quite a bit more reliable and -portable than trying to use Sys::Syslog from inside the Perl filter. Only -the first character of the level argument matters; the valid letters are -the first letters of ALERT, CRIT, ERR, WARNING, NOTICE, INFO, and DEBUG -(case-insensitive) and specify the priority at which the message is -logged. If a level that doesn't match any of those levels is given, the -default priority level is LOG_NOTICE. The second argument is the message -to log; it will be prefixed by "filter: " and logged to syslog with -facility LOG_NEWS. - -=back - -=head1 The nnrpd Posting Filter - -Whenever Perl support is needed in nnrpd, it first loads the file -_PATH_PERL_FILTER_NNRPD (defined in F, by default -F). This file must be located in the directory -specified by pathfilter in F (F -by default). The default directory for filter code can be specified -at configure time by giving the flag B<--with-filter-dir> to -configure. - -If F loads successfully and defines the Perl function -filter_post(), Perl filtering is turned on. Otherwise, it's turned off. -If filter_post() ever returns a fatal error (either from Perl or from a -C in the Perl code), Perl filtering is turned off for the life of that -nnrpd process and any further posts made during that session won't go -through the filter. - -While Perl filtering is on, every article received by nnrpd via the POST -command is passed to the filter_post() Perl function before it is passed -to INN (or mailed to the moderator of a moderated newsgroup). If -filter_post() returns an empty string (''), the article is accepted and -normal processing of it continues. Otherwise, the article is rejected and -the string returned by filter_post() is returned to the client as the -error message (with some exceptions; see below). - -filter_post() has access to a global hash %hdr, which contains all of the -headers of the article. (Unlike the innd Perl filter, %hdr for the nnrpd -Perl filter contains *all* of the headers, not just the standard ones. If -any of the headers are duplicated, though, %hdr will contain only the -value of the last occurance of the header. nnrpd will reject the -article before the filter runs if any of the standard headers are -duplicated.) It also has access to the full body of the article in the -variable $body, and if the poster authenticated via AUTHINFO (or if either -Perl authentication or a readers.conf authentication method is used and -produces user information), it has access to the authenticated username of -the poster in the variable $user. - -Unlike the innd Perl filter, the nnrpd Perl filter can modify the %hdr -hash. In fact, if the Perl variable $modify_headers is set to true after -filter_post() returns, the contents of the %hdr hash will be written back -to the article replacing the original headers. filter_post() can -therefore make any modifications it wishes to the headers and those -modifications will be reflected in the article as it's finally posted. -The article body cannot be modified in this way; any changes to $body will -just be ignored. - -Be careful when using the ability to modify headers. filter_post() runs -after all the normal consistency checks on the headers and after server -supplied headers (like Message-ID: and Date:) are filled in. Deleting -required headers or modifying headers that need to follow a strict format -can result in nnrpd trying to post nonsense articles (which will probably -then be rejected by innd). If $modify_headers is set, I in -the %hdr hash is taken to be article headers and added to the article. - -If filter_post() returns something other than the empty string, this -message is normally returned to the client as an error. There are two -exceptions: If the string returned begins with "DROP", the post will be -silently discarded and success returned to the client. If the string -begins with "SPOOL", success is returned to the client, but the post is -saved in a directory named "spam" under the directory specified by -pathincoming in F (in a directory named "spam/mod" if the post -is to a moderated group). This is intended to allow manual inspection of -the suspect messages; if they should be posted, they can be manually moved -out of the subdirectory to the directory specified by pathincoming in -F, where they can be posted by running C. If you use -this functionality, make sure those directories exist. - -=head1 Changes to Perl Authentication Support for nnrpd - -The old authentication functionality has been combined with the new -readers.conf mechanism by Erik Klavon ; bug reports -should however go to inn-bugs@isc.org, not Erik. - -The remainder of this section is an introduction to the new mechanism -(which uses the perl_auth: and perl_access: F parameters) -with porting/migration suggestions for people familiar with the old -mechanism (identifiable by the nnrpperlauth: parameter in F). - -Other people should skip this section. - -The perl_auth parameter allows the use of Perl to authenticate a user. -Scripts (like those from the old mechanism) are listed in F -using perl_auth in the same manner other authenticators are using auth: - - perl_auth: "/path/to/script/auth1.pl" - -The file given as argument to perl_auth should contain the same -procedures as before. The global hash %attributes remains the same, -except for the removal of the "type" entry which is no longer needed -in this modification and the addition of several new entries (port, -intipaddr, intport) described below. The return array now only -contains either two or three elements, the first of which is the NNTP -return code. The second is an error string which is passed to the -client if the error code indicates that the authentication attempt has -failed. This allows a specific error message to be generated by the -perl script in place of "Authentication failed". An optional third -return element if present will be used to match the connection with -the users: parameter in access groups and will also be the username -logged. If this element is absent, the username supplied by the client -during authentication will be used as was the previous behavior. - -The perl_access parameter (described below) is also new; it allows the -dynamic generation of an access group for an incoming connection using -a Perl script. If a connection matches an auth group which has a -perl_access parameter, all access groups in readers.conf are ignored; -instead the procedure described below is used to generate an access group. -This concept is due to Jeffrey M. Vinocur. - -The new functionality should provide all of the existing capabilities -of the Perl hook, in combination with the flexibility of readers.conf -and the use of other authentication and resolving programs. To use -Perl authentication code that predates the readers.conf mechanism, you -would need to modify the code slightly (see below for the new -specification) and supply a simple readers.conf file. If you don't want -to modify your code, the samples directory has F -and F which should allow you to use your old -code without needing to change it. - -However, before trying to use your old Perl code, you may want to -consider replacing it entirely with non-Perl authentication. (With -readers.conf and the regular authenticator and resolver programs, much -of what once required Perl can be done directly.) Even if the -functionality is not available directly, you may wish to write a new -authenticator or resolver (which can be done in whatever language you -prefer to work in). - - -=head1 Perl Authentication Support for nnrpd - -Support for authentication via Perl is provided in nnrpd by the -inclusion of a perl_auth: parameter in a F auth -group. perl_auth: works exactly like the auth: parameter in -F, except that it calls the script given as argument using -the Perl hook rather then treating it as an external program. - -If the processing of readers.conf requires that a perl_auth: statement -be used for authentication, Perl is loaded (if it has yet to be) and -the file given as argument to the perl_auth: parameter is loaded as -well. If a Perl function auth_init() is defined by that file, it is called -immediately after the file is loaded. It takes no arguments and returns -nothing. - -Provided the file loads without errors, auth_init() (if present) runs -without fatal errors, and a Perl function authenticate() is defined, -authenticate() will then be called. authenticate() takes no arguments, -but it has access to a global hash %attributes which contains -information about the connection as follows: C<$attributes{hostname}> -will contain the hostname (or the IP address if it doesn't resolve) of -the client machine, C<$attributes{ipaddress}> will contain its IP -address (as a string), C<$attributes{port}> will contain the client -port (as an integer), C<$attributes{interface}> contains the hostname -of the interface the client connected on, C<$attributes{intipaddr}> -contains the IP address (as a string) of the interface the client -connected on, C<$attributes{intport}> contains the port (as an -integer) on the interface the client connected on, -C<$attributes{username}> will contain the provided username and -C<$attributes{password}> the password. - -authenticate() should return a two or three element array. The first -element is the NNTP response code to return to the client, the second -element is an error string which is passed to the client if the -response code indicates that the authentication attempt has failed. An -optional third return element if present will be used to match the -connection with the users: parameter in access groups and will also be -the username logged. If this element is absent, the username supplied -by the client during authentication will be used for matching and -logging. - -The NNTP response code should probably be either 281 (authentication -successful) or 502 (authentication unsuccessful). If the code -returned is anything other than 281, nnrpd will print an -authentication error message and drop the connection and exit. - -If authenticate() dies (either due to a Perl error or due to calling die), -or if it returns anything other than the two or three element array -described above, an internal error will be reported to the client, the -exact error will be logged to syslog, and nnrpd will drop the -connection and exit. - - -=head1 Dynamic Generation of Access Groups - -A Perl script may be used to dynamically generate an access group -which is then used to determine the access rights of the client. This -occurs whenever the perl_access: is specified in an auth group which -has successfully matched the client. Only one perl_access: -statement is allowed in an auth group. This parameter should not be -mixed with a python_access: statement in the same auth group. - -When a perl_access: parameter is encountered, Perl is loaded (if it -has yet to be) and the file given as argument is loaded as -well. Provided the file loads without errors, and a Perl function -access() is defined, access() will then be called. access() takes no -arguments, but it has access to a global hash %attributes which -contains information about the connection as follows: -C<$attributes{hostname}> will contain the hostname (or the IP address -if it doesn't resolve) of the client machine, -C<$attributes{ipaddress}> will contain its IP address (as a string), -C<$attributes{port}> will contain the client port (as an integer), -C<$attributes{interface}> contains the hostname of the interface the -client connected on, C<$attributes{intipaddr}> contains the IP address -(as a string) of the interface the client connected on, -C<$attributes{intport}> contains the port (as an integer) on the -interface the client connected on, C<$attributes{username}> will -contain the provided username and domain (in username@domain form). - -access() returns a hash, containing the desired access parameters and -values. Here is an untested example showing how to dynamically generate a -list of newsgroups based on the client's username and domain. - - my %hosts = ( "example.com" => "example.*", "isc.org" => "isc.*" ); - - sub access { - %return_hash = ( - "max_rate" => "10000", - "addnntppostinghost" => "true", - # ... - ); - if( defined $attributes{username} && - $attributes{username} =~ /.*@(.*)/ ) - { - $return_hash{"virtualhost"} = "true"; - $return_hash{"path"} = $1; - $return_hash{"newsgroups"} = $hosts{$1}; - } else { - $return_hash{"read"} = "*"; - $return_hash{"post"} = "local.*" - } - return %return_hash; - } - -Note that both the keys and values are quoted strings. These values -are to be returned to a C program and must be quoted strings. For -values containing one or more spaces, it is not necessary to include -extra quotes inside the string. - -While you may include the users: parameter in a dynamically generated -access group, some care should be taken (unless your pattern is just -* which is equivalent to leaving the parameter out). The group created -with the values returned from the Perl script is the only one -considered when nnrpd attempts to find an access group matching the -connection. If a users: parameter is included and it doesn't match the -connection, then the client will be denied access since there are no -other access groups which could match the connection. - -If access() dies (either due to a Perl error or due to calling die), -or if it returns anything other than a hash as described -above, an internal error will be reported to the client, the exact error -will be logged to syslog, and nnrpd will drop the connection and exit. - -=head1 Notes on Writing Embedded Perl - -All Perl evaluation is done inside an implicit eval block, so calling die -in Perl code will not kill the innd or nnrpd process. Neither will Perl -errors (such as syntax errors). However, such errors will have negative -effects (fatal errors in the innd or nnrpd filter will cause filtering to -be disabled, and fatal errors in the nnrpd authentication code will cause -the client connection to be terminated). - -Calling exit directly, however, *will* kill the innd or nnrpd process, so -don't do that. Similarly, you probably don't want to call fork (or any -other function that results in a fork such as system, IPC::Open3::open3(), -or any use of backticks) since there are possibly unflushed buffers that -could get flushed twice, lots of open state that may not get closed -properly, and innumerable other potential problems. In general, be aware -that all Perl code is running inside a large and complicated C program, -and Perl code that impacts the process as a whole is best avoided. - -You can use print and warn inside Perl code to send output to STDOUT or -STDERR, but you probably shouldn't. Instead, open a log file and print to -it instead (or, in the innd filter, use INN::syslog() to write messages -via syslog like the rest of INN). If you write to STDOUT or STDERR, where -that data will go depends on where the filter is running; inside innd, it -will go to the news log or the errlog, and inside nnrpd it will probably -go nowhere but could go to the client. The nnrpd filter takes some steps -to try to keep output from going across the network connection to the -client (which would probably result in a very confused client), but best -not to take the chance. - -For similar reasons, try to make your Perl code -w clean, since Perl -warnings are written to STDERR. (INN won't run your code under -w, but -better safe than sorry, and some versions of Perl have some mandatory -warnings you can't turn off.) - -You *can* use modules in your Perl code, just like you would in an -ordinary Perl script. You can even use modules that dynamically load C -code. Just make sure that none of the modules you use go off behind your -back to do any of the things above that are best avoided. - -Whenever you make any modifications to the Perl code, and particularly -before starting INN or reloading filter.perl with new code, you should run -perl -wc on the file. This will at least make sure you don't have any -glaring syntax errors. Remember, if there are errors in your code, -filtering will be disabled, which could mean that posts you really wanted -to reject will leak through and authentication of readers may be totally -broken. - -The samples directory has example F, F, -F, and F files that contain some -simplistic examples. Look them over as a starting point when writing your -own. - -=head1 Available Packages - -This is an unofficial list of known filtering packages at the time of -publication. This is not an endorsement of these filters by the ISC or -the INN developers, but is included as assistance in locating packages -which make use of this filter mechanism. - - CleanFeed Jeremy Nixon - - A spam filter catching excessive multi-posting and a host of - other things. Uses filter_innd.pl exclusively, requires the MD5 - Perl module. Probably the most popular and widely-used Perl - filter around. - - Usenet II Filter Edward S. Marshall - - Checks for "soundness" according to Usenet II guidelines in the - net.* hierarchy. Designed to use filter_nnrpd.pl. - - News Gizmo Aidan Cully - - A posting filter for helping a site enforce Usenet-II soundness, - and for quotaing the number of messages any user can post to - Usenet daily.