leafnode(8)

πŸ“¦
version 1.12.0 Β· 4 versions
, in debian bookworm, debian trixie, ubuntu noble, ubuntu questing, ubuntu resolute, ubuntu stonking

🌸 NAME 🌸

okay so bestie, this is the manual page for leafnode β€” it's leafnode(8), straight out of the System Manager's Manual, and it is literally an NNTP server for small (dialup) sites. that's the whole vibe. πŸ’–


✨ SYNOPSIS ✨

leafnode

that's it. that's the whole synopsis. iconic behaviour honestly. πŸŽ€


πŸ¦‹ DESCRIPTION πŸ¦‹

leafnode is a USENET package built for small sites β€” think few users, little disk space, but a huge number of groups desired. like, tiny apartment, massive closet energy. πŸ‘‘

The design of leafnode is intended to self-repair after problems and to require no manual maintenance. she heals herself, no cap. 🧚

The leafnode program itself is the NNTP server. It gets run from inetd(8) or xinetd(8) whenever someone wants to read news. The other parts of the package β€” fetchnews and texpire β€” are responsible for fetching new news from another server, and for deleting old news. they're the girlies doing the behind-the-scenes work. πŸ’…


πŸ”’ ACCESS CONTROL πŸ”’

no authentication or access control is supported. this is a deliberate omission: implementing this is a job which should not be redone for each and every service.

It is mandatory that you use external access control mechanisms like tcpd, inetd/xinetd compiled with libwrap support option and the like β€” and that these are actually in effect. tcpd and libwrap are components of Wietse Venema's fine tcp_wrappers package.

As a very rough last line of defense against abuse, leafnode will drop connections from outside your LANs by default. You can configure leafnode to let go of this restriction (look for the allowstrangers option), but do not do that unless tight access control is in place. Someone will abuse your computer sooner or later. Promised. 😭

I recommend that either firewalling or tcpd be used for access control.


πŸ“ FILES πŸ“

All these files and directories must be readable by the user "news". It is recommended that, unless otherwise stated, the user "news" be the only user in the group "news" and these files belong to "root:news" (user:group) so leafnode cannot modify your configuration or filter files. πŸ”

/etc/news/leafnode should not be writable by the user "news", but it must be executable for at least any of the group that the user "news" is in. /etc/news/leafnode/config contains the configuration parameters for leafnode. It must not be writable by the user "news". Set this to owner root:news and mode 640. For details, see CONFIGURATION below. ✨

/var/spool/news must also be readable and writable by the user "news". It contains the news articles; e.g., /var/spool/news/alt/fan/agulbra contains the articles in the alt.fan.agulbra group. Each directory contains articles in numbered files (decimal numbers, monotonically increasing), and a special file called .overview which contains the "Subject", "From", "Date", "Message-ID", "References", "Bytes" and "Lines" headers for each article in the group. πŸ“š

Several subdirectories are special:

  • /var/spool/news/leaf.node contains the files that leafnode creates during operation, for example the groupinfo file which contains information about each USENET newsgroup. This file is built by fetchnews(8). You can force a complete rebuild of the groupinfo file by calling fetchnews with the parameter -f (see fetchnews(8)).
  • /var/spool/news/out.going contains local postings that fetchnews(8) is to pass to the upstream NNTP server. After a posting has been successfully written to disk, its u+r permission flag is set. This flag is interpreted by fetchnews(8) as "you may post this article". This prevents fetchnews from posting articles that are still being received from newsreaders. (Note: versions 1.9.23 to 1.9.32 inclusively used u+x instead, which caused some "stuck post" problems with articles in the spool when a prior leafnode version was updated to one of these 10 versions. Updating to leafnode 1.9.33 or later fixes the problem.) πŸ’€
  • /var/spool/news/failed.postings contains local postings that the upstream server rejected. fetchnews(8) will create files in this directory, but none of the leafnode programs will delete anything in it. πŸ™ˆ
  • /var/spool/news/message.id contains hard links to each message; this is used in place of the dbz database typically used by bigger servers. (A directory such as this is probably more efficient for the small servers leafnode is designed for but scales very badly.)
  • /var/spool/news/interesting.groups contains one file for each group an NNTP client has asked to read. leafnode will update the ctime (ls -l usually shows the mtime, try ls -lc) of the relevant file when a LISTGROUP, XOVER, XHDR, STAT, HEAD, BODY or ARTICLE command is issued, when a GROUP or LIST ACTIVE command (the latter only with a single group, not with patterns) is issued for an interesting group (to avoid unsubscribing low-traffic groups that are still read) and fetchnews(8) will retrieve all new articles in all groups whose files have been either
    • touched during the past two days, or
    • touched more than once, and at least once within the past week.

The timeout is configurable through the config file variables timeout_short and timeout_long. See also fetchnews(8) for the -n option. πŸ•

/etc/inetd.conf or /etc/xinetd.conf contains the configuration which starts leafnode. It is strongly recommended to start leafnode as user news. 🌟


🌈 ENVIRONMENT 🌈

  • LN_REJECT_POST_PRE β€” If this variable exists, all POST commands are rejected with a 400 code. Use only for debugging clients.
  • LN_REJECT_POST_POST β€” If this variable exists, the POST command is rejected with a 400 code after the article and CRLF.CRLF has been received. Use only for debugging clients.

πŸŽ€ CONFIGURATION πŸŽ€

All configuration is done using the file /etc/news/leafnode/config, which may include a filter description file, filterfile for short, as described below. πŸ’…

For the purposes of this section, whitespace shall be defined as an arbitrary sequence consisting of one or more SPACE or HTAB characters, ASCII positions 32 and 9, respectively.

The configuration file is strictly line-oriented with LF or CRLF as line terminator.

Empty lines and lines consisting of only whitespace, possibly followed by a comment (introduced by a hash mark (#) and extending through the end of the line), are skipped. 🚫

All other lines have exactly three mandatory fields: a plain text parameter, an assignment character (=) optionally surrounded by whitespace, and a value. The value is either plain text or β€” new since leafnode v1.11 β€” a string in double quotes with trivial backslash escape (see below).

Plain text starts at the first non-whitespace character and extends through the last non-whitespace character on the line that is not a comment. A trailing comment on a line is skipped.

Quoted strings are enclosed in double quote characters ("). The backslash character (\) is skipped, but it copies the immediately following character verbatim, so that you can specify the backslash itself by doubling it (\\) or a double quote character as part of the string by preceding it with a backslash (\"); the hash mark has no special meaning as command introducer inside quoted strings. Text after the end of the string is silently ignored (this may change in future versions). Comments after quoted strings are ignored. 🎯

πŸ’– MANDATORY PARAMETERS πŸ’–

These parameters must be specified for leafnode to work. no skips, bestie.

  • server = news02.example.com β€” "server" is used by fetchnews(8) to select what NNTP server(s) to retrieve news from and to post your articles to. You can specify more than one news server; in that case, the servers will be queried from the top down. If you want to post articles, at least one of your servers should allow you to post. In the example above, news02.example.com is the news server.

This parameter can be given more than once. Each server starts with a fresh set of default configuration options, no inheritance takes place from the previous server definition. Only options explicitly marked "server-specific" can be set on a per server basis, "general" options are set for all servers at the same time. πŸ‘‘

  • expire = 5 β€” "expire" is the number of days an article should be kept around. In the example, five days after the article has last been read, it is deleted by texpire(8). This value MUST be at least 1. This parameter is global, see the introductory paragraph of the following GENERAL OPTION PARAMETERS section to find out what this means. πŸ—“οΈ

🌟 GENERAL OPTIONAL PARAMETERS 🌟

These options can only be configured once in the configuration file, and take effect for leafnode as a whole. It does not matter where these are specified relative to server= options, but for clarity, you are encouraged to place these before the first server= line. Specifying each of the global options more than once lets the last copy take effect, but may cause errors in the future. 😬

  • hostname = host.domain.country β€” By default, leafnode tries hard to figure the host name of your computer, skipping inadequate (non-unique) names if possible. It will look up your computer's host name with gethostname(3) and then try to qualify the name with gethostbyname(3) if necessary. Common sources for the full name therefore are /etc/hosts, NIS and DNS, but consult your system documentation for details.

If leafnode fails to determine the host name, this is usually a hint that your system is not configured properly, or it has a hostname that is unsuitable for the domain part of a Message-ID, for example, "localhost.localdomain", and you should fix the name service configuration. Adding a unique fully-qualified host name to /etc/hosts is usually sufficient. Please see README-FQDN for more details.

You can configure the unique fully-qualified host name here as well, but this is not recommended and discouraged.

  • create_all_links = 1 β€” Normally, fetchnews will store articles only in the newsgroups which it considers interesting. With this option set, fetchnews will create hardlinks for all newsgroups in the Newsgroups: header that it knows about. This may be of interest if you want to apply a score- or killfile to the local Xref: line. πŸ”—
  • maxfetch = 1000 β€” "maxfetch" specifies the maximum number of articles fetchnews(8) should fetch from the upstream server in each group. Its use is not advised, because if you use it you will not see all the traffic in a group. By default there is no limit. ⚠️

okay that's part one bestie, there's more coming so don't go anywhere πŸ’œ

  • initialfetch = 1 β€” bestie, this one decides how many articles get pulled down from a group you just subscribed to. Default behaviour? Grab every single old article, which is giving "why is my terminal frozen" when you subscribe to a truly cursed busy group. That default is the same as setting initialfetch to zero. Want zero old articles on a fresh subscribe? Set initialfetch to one, exactly like the example above. 🫢
  • groupexpire very.crowded.group = 1
  • groupexpire very.crowded.hierarchy.* = 1 β€” groupexpire is your little ✨per-group expiry remote✨. Expiry times go in days. 0 means "just use the default", and negative values stop the expire process for that group entirely (think of it as archive mode, lowkey iconic). This value gets used by texpire (8). You can write as many groupexpire lines as your heart desires, and glob (7)-like wildcard expressions are totally allowed. 🌈
  • maxage = 10 β€” if an article shows up on your upstream news server and it's older than maxage days, it will not be fetched, even if you don't have it yet. Super useful when your upstream server has one of its occasional "hiccups" πŸ’€. Default is 10. Wanna switch the whole feature off? Set maxage to some very large value like 20000 (that's roughly 54 years, no cap).
  • maxold = 10 β€” literally just a synonym for maxage, see above. Same vibes, different name. πŸ’…
  • maxlines = 2000 β€” trying to dodge absolutely massive articles? Set maxlines to the max number of lines an article is allowed to have. By default this feature is switched off. ✨
  • minlines = 2 β€” sometimes newsgroups get spammed with empty postings and it's giving nothing. To reject them, set minlines. Setting minlines higher than 4 is probably not it, since you'll start killing "real" postings too 😭. By default, off.
  • maxbytes = 100000 β€” same energy as maxlines but by size instead: if you want to avoid very large articles, use maxbytes instead. By default, switched off. πŸ¦‹
  • maxcrosspost = 5 β€” spam combat mode πŸ”₯. Filter out every posting that's posted to more than a certain number of newsgroups by setting maxcrosspost. Setting it to very low values is probably a bad idea, ngl. Switched off by default.
  • maxgroups = 5 β€” synonymous for maxcrosspost. See above. πŸ‘‘
  • filterfile = /etc/news/leafnode/filters β€” leafnode can filter the input headers for arbitrary regular expressions, and they live in a file called filterfile. The format is so simple: one perl-compatible regular expression per line. If any of those regexes fits a header that's about to be downloaded, the body of that article gets rejected. Off by default. The format of those regular expressions is described in pcre(3). πŸŽ€
  • timeout_short = 2 β€” by default, a group that was accidentally touched keeps getting fetched for two days. Change that window with timeout_short.
  • timeout_long = 7 β€” by default, a group that hasn't been read at all keeps getting fetched for seven days before it gets unsubscribed. Set timeout_long to something else to change that interval.
  • timeout_active = 90 β€” by default, active files from the upstream servers get re-read every 90 days. Change it with timeout_active. ⚠️ Heads up: reading an active file transfers about one MB of information if the server you're using carries a reasonable number of groups (i.e. around 20,000).
  • timeout_client = 900 (since v1.9.23) β€” by default, leafnode drops the connection 900 seconds (15 minutes) after seeing the last command from the client. You can change the timeout here. Setting it too low (like below 5 minutes) will annoy your users and burn more system resources re-reading all the files. Don't do that to them. πŸ™ˆ
  • timeout_fetchnews = 300 (since v1.9.52) β€” since v1.9.52, fetchnews assumes the upstream server has become wedged after waiting 300 seconds for a reply. Change the timeout here.
  • timeout_lock = 5 (since v1.9.54) β€” configure how many seconds the leafnode programs (applyfilter, checkgroups, fetchnews, texpire) will wait for the lock file before aborting. Setting it to 0 means wait indefinitely. πŸ“Œ NOTE: you can override this by setting the environment variable LN_LOCK_TIMEOUT (note it is not LN_TIMEOUT_LOCK). Default is 5 seconds.
  • delaybody = 1 β€” with this set, fetchnews (8) fetches only the headers of an article so you can eyeball them first πŸ‘€. Only once the headers have been read do the bodies get retrieved the next time fetchnews (8) is called. Saves a huge amount of download time and disk space. Slay.
  • delaybody_in_situ = 1 (since v1.9.41) β€” only applicable with delaybody=1.

By default, leafnode gives the fully downloaded article a brand new article number so it looks new in your newsreader. This doesn't work for all newsreaders though. With this option set, leafnode keeps the original article number. You'll have to figure out how to tell your newsreader to show old articles. This option defaults to 0, and it is highly recommended to leave it unset. 🚩

  • debugmode = 1 β€” with this set, fetchnews (8), texpire (8) and leafnode (8) start logging lots of debugging output via syslog (8) at facility news and priority debug. Use it for tracking down problems with your feed. Leave debugmode at 0 for regular use, because it can log enormous amounts of data 😭. The higher the number, the more gets logged β€” but choosing a figure greater than 3 won't make a difference at the moment.
  • allow_8bit_headers = 1 (since v1.9.25) β€” by default, leafnode rejects local posts that have 8-bit characters in their headers, because they violate relevant standards, particularly RFC-2822 (which RFC-1036 is based on), which demands that Usenet news headers (as mail headers) must be pure 7-bit US-ASCII, with only whitespace allowed from the control characters. Periodt.

However β€” as UTF-8 is to come, and some national hierarchies, particularly the Norwegian and Danish (no.*, dk.*), seem to have agreed on preferring just-send-eight over RFC-2047, you can set this option to allow 8-bit data in headers. Leafnode will however add a warning header if 8-bit data is present, stating that the site administrator allowed this.

There is no way to make leafnode accept non-whitespace control characters in headers. None. Zero. 🚫

  • allowSTRANGERS = MAGIC (since v1.9.23) β€” by default, leafnode refuses connections from outside your LANs. Check config.example for how to use this parameter to let strangers connect to your leafnode. Instead of MAGIC, you have to write a number as mentioned in config.example. πŸ“Œ Note that capitalization matters β€” allowSTRANGERS is not allowstrangers, bestie.
  • linebuffer = 1 β€” by default, stdout and sometimes stderr of applications are set to "fully buffered" unless connected to terminals. Use this option to explicitly request line buffered mode for stdout and stderr. ✨
  • clamp_maxage = 0 β€” by default, leafnode derives a maxage argument from the expire time applicable to the group (groupexpire if set, expire otherwise), so it doesn't re-fetch articles that were once there and then cleared by texpire(8). Set clamp_maxage=0 to get rid of this behaviour.
  • article_despite_filter = 1 (since v1.9.33) β€” by default, fetchnews requests HEAD and BODY separately if a filter file is defined and delaybody is off. For high latency, high throughput links (like interleaved DSL or satellite links), it may be faster to request head and body together with an ARTICLE command and just ignore the body if the filters apply β€” though it may not be cheaper if you pay per MByte πŸ’Έ. Enabling this option forces leafnode to use the ARTICLE command in spite of filters being defined. (Note that in delaybody mode, HEAD and BODY will ALWAYS be requested separately.)
  • newsadmin = news@leafnode.example.org (since v1.9.47) β€” this option sets the From: address for the placeholder article, and it should be the news administrator's mail address. It defaults to news@HOSTNAME, where HOSTNAME is leafnode's hostname. πŸŽ€

🌈 SERVER-SPECIFIC OPTIONAL PARAMETERS 🌈

These options can only be placed after the server= line of the server you want them to apply to, and they always pertain to the preceding server= line. Specifying them before the first server= line is an error. πŸ™…β™€οΈ

  • username = myname β€” if any of your news servers requires authentication, drop your username for that server here. This field may occur multiple times, once after each server definition. See the introduction of this CONFIGURATION section for info on how to quote myname. πŸ’…
  • password = mypassword β€” same deal, if a news server needs authentication, your password goes here. This field may occur multiple times, once after each server definition. 🚩 Since the password is available in clear text, it is recommended that you set the rights on the config file as restrictive as possible β€” otherwise other users of your computer will be able to get your password(s) from that file. Lock it down, bestie. See the introduction of this CONFIGURATION section for info on how to quote mypassword.
  • port = 8000 β€” by default, fetchnews tries to connect to its upstream news servers on the NNTP port (119). If your servers run on a different port, specify it here. This field may occur multiple times, once after each server definition.

Note: to modify the port your own leafnode server listens on, change the inetd.conf or xinetd.conf configuration file. leafnode does not set up its listen port itself. πŸ¦‹

  • timeout = 30 β€” bestie, by default leafnode tries to connect for 10 seconds to a server and then it's like "k bye". If your server is slow af, you can try longer by setting the timeout higher (in this example, 30 seconds). The timeout can be tuned individually for each server, no cap.
  • noactive = ANYTHING (v1.9.25 ... v1.11.4) / noactive = 1 (since v1.11.5) β€” if this parameter is set, the active file is never downloaded from this server. Use this for very slow servers unless they carry groups that other servers do not offer. Leafnode versions 1.9.25 to 1.11.4 would always assume that "ANYTHING" had been 1. "noactive = 0" is supported since v1.11.5.
  • nodesc = ANYTHING (until v1.11.4) / nodesc = 1 (since v1.11.5) β€” some servers do not deliver news group descriptions correctly because they cannot parse the XGTITLE and LIST NEWSGROUPS commands. In that case, put this line after the "server" line. Leafnode versions up to v1.11.4 would always assume that "ANYTHING" had been 1. "nodesc = 0" is supported since v1.11.5.
  • nopost = 1 (since v1.9.23) β€” prevent posting to this server. You can use this if the upstream will not let you post but still greet leafnode with 200 or if the upstream does not forward your postings reliably.
  • noread = 1 (since v1.9.33) β€” prevent fetching news articles or active files from this server. You can use this if the upstream is good to post, but too slow to fetch news from. bestie said "read? never heard of her"
  • noxover = 1 (since v1.9.47) β€” prevent the use of XOVER on the current server. Fetchnews will use XHDR instead.
  • only_groups_match_all = 1 (since v1.9.52) β€” usually, when cross-posting an article, fetchnews will post the article if ANY group listed in the Newsgroups: header is matched by the PCRE. With this option on, ALL groups listed in the Newsgroups: header must match. This can be used to avoid "poison" groups when you have multiple upstream servers.
  • only_groups_pcre = PCRE (since v1.9.28) β€” this parameter lists the Perl-compatible regular expression of groups that are fetched or posted to this server. The PCRE is automatically anchored at the left hand side, so you can omit the leading ^. Remember to escape dots, as in:
de\.comp\.|de\.comm\.

If this parameter is omitted, all groups are fetched from and posted to this server.

Note: you must run fetchnews with the -f option after changing, adding or removing any only_groups_pcre option.
Hint: you can use something like this to check your only_groups_pcre settings: cut -f1 -d" " @spooldir@/leaf.node/groupinfo \ | pcregrep 'PATTERN'
  • post_anygroup = 1 (since v1.9.37) β€” this parameter makes leafnode post on this server without checking if it carries the group an article is posted to. The default is post_anygroup = 0, which means that leafnode will check with a "GROUP" command if the server carries the group the articles is posted into. Use this on post-only servers that do not allow the "GROUP" command.
Note: inconsiderate use of this parameter may cause articles to end up in the failed.postings directory. πŸ’€

πŸ‘» OBSOLETE PARAMETERS πŸ‘»

  • supplement β€” is synonymous to server. Do not use it on new installations. it's giving deprecated, bestie, don't do it.
  • fqdn β€” is synonymous to hostname. Do not use it on new installations. same vibe, same warning.

πŸ“‘ PROTOCOL πŸ“‘

Here are the NNTP commands supported by this server:

ARTICLE, BODY, DATE, GROUP, HDR, HEAD, HELP, LAST, LIST, LIST ACTIVE, LIST ACTIVE.TIMES, LIST EXTENSIONS, LIST NEWSGROUPS, LIST OVERVIEW.FMT, LISTGROUP, MODE, NEWGROUPS, NEXT, POST, OVER, SLAVE, STAT, XHDR, XOVER. These commands follow RFC-977 and RFC-2980, except HDR and OVER which are recognized in anticipation of current NNTP drafts.

Note: the syntax of HDR and OVER may change. πŸ‘€

πŸ› BUGS πŸ›

  • Leafnode is totally unaware of UTF-8 and will reject a client that posts UTF-8 characters in the header. Current Usefor drafts claim all article headers UTF-8 encoded Unicode. Leafnode still expects RFC-2047 instead which may eventually be phased out in favour of UTF-8. it's not a phase, mom, it's RFC-2047.
  • Leafnode stops reading a line at the first NUL character. literally stops dead.
  • Leafnode may not cope well with crosspostings that cross hierarchies if you have multiple upstream feeds and use the only_groups_pcre configuration option. iykyk.
  • Leafnode will only bother to determine the time zone offset for generated Date: headers for posts that lack them on systems that offer the tm_gmtoff member in struct tm (commonly BSD and GNU systems). if your system doesn't have it, leafnode is like "not my problem bestie".

πŸ’– AUTHOR πŸ’–

Written by Arnt Gulbrandsen <agulbra@troll.no> and copyright 1995 Troll Tech AS, Postboks 6133 Etterstad, 0602 Oslo, Norway, fax +47 22646949.

Modified by Cornelius Krasel <krasel@wpxx02.toxi.uni-wuerzburg.de>, Randolf Skerka <Randolf.Skerka@gmx.de> and Markus Enzenberger <enz@cip.physik.uni-muenchen.de>. Copyright of the modifications 1997 – 1999.

Modified by Matthias Andree <matthias.andree@gmx.de>, Copyright 1999 – 2002. Modified by Ralf Wildenhues <ralf.wildenhues@gmx.de>, Copyright 2002.

Jonathan Larmour <jifl@jifvik.org> contributed the timeout_client feature.

Andreas Meininger <a.meininger@gmx.net> contributed the code to let texpire ignore groupexpire = -1 groups.

Mark Brown <broonie@debian.org> added the noactive option.

Numerous contributions by other people. the whole squad ate, no crumbs.

The initial development of leafnode has been paid for by Uninett AS (http://www.uninett.no/).


πŸ‘€ SEE ALSO πŸ‘€

applyfilter(8), checkgroups(8), fetchnews(8), newsq(1), texpire(8).

tcpd(8), hosts_access(5), glob(7), pcre2(3), RFC 977, RFC 2980.


okay that's the whole vibe bestie, you made it to the end of the leafnode(8) manual page β€” this is from leafnode 1.12.0, dated as it says on the page (leafnode(8)), and you're officially iconic for reading all of it. slay. πŸ’…βœ¨πŸ¦‹

πŸ“¦ where this page comes from