Newsserver einrichten

Aus wiki.freifunk.net
Zur Navigation springenZur Suche springen

INN2

InterNetNews ist ein nntp Server für Linux. Die nachstehende Anleitung zeigt, wie man mit inn2 einen Newsserver für Freifunk aufsetzt.

Installation

Unter Debian:

sudo aptitude install inn2 suck

Konfiguration

Alle Konfigurationsdateien liegen in /etc/news/

  • Zuerst einmal muß die Hauptconfig angepasst werden. Diese liegt als /etc/news/inn.conf vor.

Die Parameter organization und pathhost sollten auf jeden Fall angepasst werden.

organization:           "Freifunk Leipzig"
pathhost:               news.leipzig.freifunk.net

Auf Systemen mit mehreren IP Adressen ist es zusätzlich sinnvoll, den inn2 an eine bestimmte Adresse zu binden:

bindaddress:            88.198.44.10
  • Anschließend zur /etc/news/expire.ctl hinzufügen:
freifunk.*:A:never:never:never

Dies sorgt dafür, daß die Nachrichten nicht auslaufen und dauerhaft vorgehalten werden. Andere Werte sind natürlich auch möglich, falls der Speicherplatz begrenzt ist.

  • Zur /etc/news/control.ctl hinzufügen:
# freifunk
newgroup:*:freifunk.*:doit
rmgroup:*:freifunk.*:doit

Damit wird das automatische Erzeugen und Löschen von Gruppen durch control Nachrichten innerhalb der freifunk.* Hierarchie erlaubt.

  • /etc/news/actsync.ign anlegen mit folgendem Inhalt
# Don't touch control groups, etc.
i control
i control.*
i local.*
i general
i junk

Diese Datei stellt sicher, dass beim Abgleich der Liste der Gruppen lokalen Systemgruppen nicht gelöscht werden.

  • mit /etc/news/readers.conf wird der Zugriff auf den Newsserver reguliert
# Clients die aus einem der in "hosts" angegebenen Adressbereiche connecten 
# erhalten den pseudo Usernamen "freifunk" ...
auth "freifunk" {
    hosts: "104.0.0.0/8"
    default: "freifunk"
}

# ... diesen wird dann einfacher lesender und schreibender Zugriff auf
# die freifunk.* Hierarchie erlaubt.
access "freifunk" {
    users: "freifunk"
    newsgroups: "freifunk.*"
}

Wichtig: Der letzte passende Eintrag gilt, d.h. allgemein gefasste Einträge müssen vor spezifischen Einträgen stehen. Dies gilt insbesondere auch für eventuelle Server, wie weiter unten gezeigt.

Benutzerauthentifizierung

Mit diesem Perl Script kann man eine Benutzerauthentifizierung gegen die FFsomething Benutzerdatenbank durchführen.

Dazu muss in die readers.conf Folgendes vor den anderen Einträgen hinzugefügt werden:

# Login mit FFsomething Benutzerkennung
auth "freifunk" {
    auth: /etc/news/filter/ffsomething_auth.pl
}

SSL Verschlüsselung

Obwohl die SSL Funktionen von inn2 nicht mit Thunderbird und möglicher Weise anderen Clients kompatibel sind, kann man optional einen SSL Verschlüsselung für die Benutzer mit Hilfe von stunnel und inetd realisieren.

  • in /etc/inetd.conf eintragen
nntps stream tcp nowait root /usr/bin/stunnel stunnel -p /usr/lib/news/cert.pem -s news -g news -r nntp

Synchronisation

Es gibt zwei Möglichkeiten einen INN zu füttern. Entweder man syncronisiert passiv durch pull der Nachrichten, oder man wird gefüttert von einem Upstream (statische IP nötig).

Die Gegenstelle muß euch erlauben, die Nachrichten abzuholen bzw. sie Euch zuschicken. Daher müsst ihr auf einem der großen Newsserver nach einem Upstream fragen. Am besten von zwei, damit eine gewisse Redundanz entsteht.

Pull

Fürs pullen am Besten suck installieren.

  • /etc/cron.d/inn2 eintragen
# update active list every day
3 3     * * *   news    /usr/lib/news/bin/actsync -A localhost UPSTREAM -v 1 -p 0 -o x -i /etc/news/actsync.ign
# suck new articles every five minutes
*/5 *   * * *   news    suck UPSTRAM -U LOGIN -P PWD -bp -hl localhost -q -s -A -c 2>/dev/null >/dev/null

falls eine Meldung wie diese kommt:

200 UPSTREAM InterNetNews server INN 2.5.2 ready (transit mode)
GROUP <freifunk.de.berlin.discuss>, unexpected response, 401
Broken connection, aborting 
Elapsed Time = 0 mins 0.00 seconds
Closed connection to <UPSTREAM>

muss suck im Cronjob um die Option -M ergänzt werden. Damit teilt man dem Server mit, dass er

*/5 *   * * *   news    suck UPSTRAM -U LOGIN -P PWD -bp -hl localhost -q -s -A -c -M 2>/dev/null >/dev/null

Newsfeeds

Newsfeeds sind eigentlich eine saubere Lösung. Die meisten Newsserver auf diesem Planeten verwenden reguläre Newsfeeds um ihren Datenbestand auszutauschen. Allerdings funktionieren Newsfeeds nur mit statischen IP Adressen größtenteils ohne Probleme. Bei Servern mit dynamischen IP Adressen sollte man keine Newsfeeds einsetzen, da es regelmäßig zu Verbindungsabbrüchen kommt und der Austausch von Daten nicht gewährleistet werden kann.

Man kann einen ausgehenden Feed entweder mittels nntpsend (zeitverzögert) oder innfeed (echtzeit) konfigurieren.

Empfang

  • in /etc/news/readers.conf hinter den allgemeinen Einträgen
# Den hier in der "hosts" Zeile eingetragenen Rechnern wird
# der pseudo Username "server" zugewiesen ...
auth "server" {
    hosts: "peer-1.fqdn.tld, peer-2.fqdn.tld, ..."
    default: "server"
}

# ... welcher erhöhte Privilegien erhält.
access "server" {
    users: "server"
    newsgroups: "*"
    access: "RPIAN"
}

Hier wird allen Peers der Pseudo-User "server" zugewiesen. Dieser User hat mehr Berechtigungen welche z.B. zum Synchronisieren und Feeden gebraucht werden.

Möglicher Weise gibt es Probleme mit Reverse Lookup, weshalb die Verwendung von IP Adressen anstelle von Hostnamen hier eigentlich die bessere Wahl ist.

  • in /etc/news/incoming.conf
group freifunk {
        peer peer1 {
                hostname: "peer-1.fqdn.tld"
        }
        peer peer2 {
                hostname: "peer-2.fqdn.tld"
        }
        ...
}

Als Peer trägt man einen beliebigen Bezeichner ein und als Hostnamen den jeweiligen FQDN oder die IP Adresse. Auch hier sind die IP Adressen eventuell besser, um Probleme zu vermeiden.

Versand (echtzeit)

  • in /etc/news/newsfeeds
innfeed!\
        :!*\
        :Tc,Wnm*:/usr/lib/news/bin/startinnfeed

peer1:*,!junk,!local*:Tm:innfeed!
peer2:*,!junk,!local*:Tm:innfeed!

Hier wird zunächst ein Sammelfeed ("funnel") definiert, der über das externe Programm innfeed versendet wird. Anschließend wird festgelegt, dass für die genannten Peers alle News-Gruppen außer "junk" und "local.*" an diesen funnel übergeben werden sollen.

  • in /etc/news/innfeed.conf
group freifunk {
        peer peer1 {
                ip-name: "peer-1.fqdn.tld"
        }
        peer peer2 {
                ip-name: "peer-2.fqdn.tld"
        }
}

In dieser Datei werden die vollständigen Hostnamen bzw. IP Adressen für jeden Peer (Ziel) konfiguriert.

Versand (zeitversetzt)

Wenn ihr feeds in bestimmten Intervallen zu anderen Servern schicken möchtet:

  • in /etc/news/newsfeeds:
peer1:*,!local*,!junk:Tf,Wnm:
peer2:*,!local*,!junk:Tf,Wnm:
peer3:*,!local*,!junk:Tf,Wnm:
...

Die einzelnen Zeilen legen fest wohin lokale Posts verteilt werden sollen, gefiltert nach Gruppen. In unserem Beispiel werden alle lokalen Gruppen außer die internen "junk" und "local.*" Gruppen an alle Peers verteilt. Die Nachrichten werden zunächst in eine lokale Datei geschrieben.

  • in /etc/news/nntpsend.ctl:
peer1:peer-1.fqdn.tld::-t180
peer2:peer-2.fqdn.tld::-t180
peer3:peer-3.fqdn.tld::-t180
...

Hier wird festgelegt welche Peers vom eigenen Server versorgt werden. "peer-n.fqdn.tld" wird hierbei durch den voll qualifizierten Hostnamen oder die statische IP-Adresse des jeweiligen Peer-Servers ersetzt.

  • in /etc/news/passwd.nntp
peer1:user:password
peer2:user:password

Dieser Eintrag wird nur benötigt, falls der Zielserver ein Passwort verlangt. Der Benutzernamen und das Passwort zum Synchronisieren muss beim jeweiligen Betreiber des Peers erfragt werden.

  • in /etc/cron.d/inn2
*/5 * * * * news /usr/lib/bin/nntp-send peer1 peer2 peer3

Dieser Eintrag sorgt dafür, dass die lokal gesammelten Nachrichten alle fünf Minuten an den/die Zielserver gesendet werden. Die Zielserver können alle in einer Zeile hintereinander aufgeführt werden.

Letzte Schritte

  • Starten des inn2 Servers
/etc/init.d/inn2 start
  • Beim ersten Start sollte noch mit einem der Upstreams synconisiert werden. Als root eingeben:
su - news
/usr/lib/news/bin/actsync -A localhost UPSTREAM -v 1 -p 0 -o x

Dies aktualisert das active file, also die Liste aller auf dem Newsserver aktiven Newsgroups.

  • bisher vorhandene Artikel holen
suck UPSTREAM -U LOGIN -P PWD -bp -hl localhost -q -s -A -c 2>/dev/null >/dev/null 

füllt erstmal den Newsserver mit allen Nachrichten vom Upstream, damit er nicht so leer ist :)

  • suck evtl. um -M ergänzen (siehe #Pull)
  • um alle historischen Artikel vom Upstream zu bekommen, muss in inn.conf der Parameter artcutoff auf 0 gesetzt werden. Alle anderen positiven Zahlen zeigen das maximale Alter der zu importierenden Artikel an.
  • suck lädt standardmäßig nur die 100 neuesten Artikel, so dass man zusätzlich -i 0 als Parameter anhängen muss, um alle Artikel zu laden

Verschlüsselung einrichten

Als erstes brauchen wir ein Certifikat. Ein self-signed erstellt man einfach so

 openssl req -new -x509 -nodes -days 365 -keyout /etc/news/nnrpd-key.pem -out /etc/news/nnrpd-cert.pem

Um dieses Cert für TLS zu verwenden muß man es nur noch einbinden:

/etc/news/inn.conf

 tlscapath:             /etc/news
 tlscertfile:           /etc/news/cert.pem
 tlskeyfile:            /etc/news/key.pem

Nach einem innd Neustart solltre TLS funktionieren.

Um nntps ans laufen zu bringen muß man etwas weiter ausholen. die Lösung mit stunnel funktioniert zwar, ist aber ein Sicherheitsloch - denn auf einmal kommen alle Verbindungen von localhost - der meistens mehr Berechtigungen hat als ein normaler User. Sauberer ist es innd über xinetd zu starten mit der Option für SSL ( -S ).

/etc/xinetd.d/nntpd

 service nntps
 {
   disable = no
   socket_type = stream
   protocol = tcp
   user = news
   wait = no
   server = /usr/lib/news/bin/nnrpd
   server_args = -S
   per_source = 4
   instances = 200
   log_on_success += DURATION HOST USERID
 }

xinetd neustarten und es sollte funktionieren.

Newsgroup Anlegen

ctlinnd newgroup freifunk.de.NAME

Synchronisation mit Mailinglisten

Die bequeme Art

Wird die Mailingliste von Mailman verwaltet, kann man dort im Administrationsmenü eine Kopplung zu einer Newsgroup einrichten. Es reicht, die Newsgruppe und den Newsserver anzugeben. Auf INN2-Seite muss die IP-Adresse oder der DNS-Name des Mailmanservers in der Konfiguration der Newsfeeds beschrieben in /etc/news/readers.conf sowie in /etc/news/incoming.conf eingetragen werden.

Pferdefuß an diese Lösung ist, das in vielen Mailman-Installationen ein Cron-Job nicht gestartet wird, der neue Nachrichten aus den Newsgruppen abholt. Entweder hostet man Mailman selbst, man kann seinen Mailman-Admin überzeugen oder man greift auf Lösung 2 zurück.

Für Listen auf @freifunk.net ist der Cron-Job aktiviert und diese Listen können synchronisiert werden. Falls ihr euren Mailman-Admin bekehren wollt, er/sie muss nur diese Einstellung ändern (Info von In-Berlin):

Das relevante Skript dafür ist cron/gate_news, bei uns konkret sieht der Eintrag so aus ($mailmandir ist das Verzeichnis, in dem Mailman installiert ist, z.B. /usr/local/mailman):

   */5 * * * *       mailman /usr/bin/python -S $mailmandir/cron/gate_news

Die funktionierende Lösung

Diese Lösung erfordert deutlich mehr Aufwand zur Einrichtung, aber hier hat der Adminitrator des Newsservers die Synchronisation in der Hand. Mit dieser Lösung wird in Weimar und Hamburg gearbeitet.

Voraussetzungen Software

  • Procmail und Postfix müssen installiert sein
  • Newsserver ist fertig konfiguriert
  • Newsgruppen für die zu synchronisierenden Mailinglisten sind angelegt

Voraussetzungen Mailingliste

  • Eine Emailadresse, die der Server empfangen kann registriert man für jede Mailingliste, die man synchronisieren möchte bei der jeweiligen Mailingliste, z.B. <listenname>@<serverdomain>.<tld>. Wichtig ist, dass es jeweils andere Adressen sind.
  • in der Mailingliste konfiguriert man die Emailadresse so, dass sie alle Nachrichten als Einzelnachrichten bekommt, nur die eigenen Nachrichten lässt man sich nicht zusenden

Anpassungen von INN2-Skripten

Die Skripte für das posten von Mails auf Newsgruppen und das Versenden von Newseinträgen auf Mailinglisten müssen etwas angepasst werden. Die Anweisungen und Diffs sind in http://batleth.sapienti-sat.org/projects/news2mail/news2mail-FAQ-en.html zu finden. Da die Versionen recht alt sind kann das Patchen fehlschlagen oder ungültige Dateien erzeugen. Wendet euch bei Fragen an Andibraeu (Diskussion)

  • /usr/lib/news/bin/mailpost
    • path enthält dann mailpost, als Kennzeichen für news2mail, dass die Mail von der Liste kam und nicht nochmal hingeschickt werden muss
    • leere Subjects werden aufgefüllt
    • cc und reply-to werden gesetzt
    • organization wird gesetzt
  • /usr/lib/news/bin/news2mail
    • Korrektur von Headerfeldern

Konfiguration des Newsservers

In /etc/news/newsfeeds muss diese Zeile genau einmal auftauchen: news2mail!:!*:Ac,Tc,Wn*:/usr/lib/news/bin/news2mail Eventuell existiert sie schon oder beginnt mit n2m. Für jede zu synchronisierende Mailingliste sind diese beiden Konfigurationsschritte notwendig:

  • ans Ende von /etc/news/newsfeeds kommt absenderemail@adresse.de/mailpost:!*,<newsgroup>:Tm,Ac:news2mail!
    • die Absenderemail entspricht der oben registrierten Emailadresse
    • für newsgroup wählt man die Gruppe aus, die mit der Mailingliste synchronisiert werden soll, z.B. freifunk.de.<stadtname>
  • ans Ende von /etc/news/news2mail.cf kommt absenderemail@adresse.de zieladresse@mailingliste.com
    • die Absenderadresse entspricht der in newsfeeds angegebenen Adresse
    • die Zieladresse ist die, mit der man normalerweise an die Mailingliste schreibt

Einrichten eines Aliases

Eingehende Emails werden von Postfix entgegengenommen und können dann weiter verarbeitet werden. Mit einem Alias kann man Emails an bestimmte Adresse z.B. per Pipe weiterverarbeiten, was wir hier ausnutzen.

  • in /etc/aliases trägt man nun den Alias mit dem auszuführenden Kommando ein: listenname: "| sed -e 's/\\[Freifunk[^]]*]//g' | /usr/bin/formail -f -c -z -U Content-Transfer-Encoding: -I X-Trace: -I X-Complaints-To: | /usr/lib/news/bin/mailpost newsgroup"
    • listenname entspricht der anfangs registrierten Emailadresse
    • der sed-Befehl entfernt in diesem Fall Ergänzungen im Subject, die mit [Freifunk beginnen
    • formail entfernt störende Header
    • mailpost schickt den Artikel dann an die newsgroup
  • zuletzt muss noch newaliases ausgeführt werden, um den neuen Alias wirksam werden zu lassen

Um die Kiddies daran zu hindern, das Passwort für den Mailinglistensubscriber auf die Liste zu posten, kann man in Postfix header_checks einbauen:

  • postfix-pcre nachinstallieren
  • Datei /etc/postfix/header_checks anlegen
 /^From: bounces-adresse@mailman/ REDIRECT user@domain
 /^From: request-adresse@mailman/ REDIRECT user@domain
  • /etc/postfix/main.cf um header_checks = pcre:/etc/postfix/header_checks ergänzen
  • postfix neustarten
  • fertig

Dokumentation

Dokumentation zu Inn2 findet sich u.A. unter http://www.eyrie.org/~eagle/software/inn/

Peeringliste

Server welche zum Peering offen sind und die Freifunk Hierarchie beinhalten.

Server Admin Peerings
news.leipzig.freifunk.net freifunk [ät] poelzi {dot} org news1.halle, news2.leipzig, news.hannover, news.weimar
news2.leipzig.freifunk.net freifunk {at} wwsnet {dot} net news1.halle, news.leipzig
news1.freifunk-halle.de se nada1 de news.leipzig, hannover
news.weimarnetz.de freifunk andi95 de leipzig, hamburg, gronau
news.hamburg.freifunk.net andre hamburg freifunk net weimar

Nur Mesh-Intern:

Name IP Admin Peerings
news.gronau.ff 10.244.16.1 freifunk ! liztv.net news.weimar

Mailman 2.1.9 Patch für Message-ID-Handling

Mailman ändert standardmäßig die Message-IDs von NNTP-Postings um Duplikate zu vermeiden. Das hat den Nebeneffekt, das das Threading zwischen News und Mail nicht mehr sauber funktioniert da die Nachrichten ihre Bezüge zueinander verlieren. Zusätzlich haben NNTP-Postings, die in Mailinglisten erscheinen, zusätzlich einen Newsgroups-Header gesetzt, welcher manche Mail-Clients veranlasst die Antwortadresse auf die Ursprungs-Newsgroup statt auf die Liste zu setzen.

Der folgende Patch behebt die Probleme:

Index: mailman-2.1.9/cron/gate_news
===================================================================
--- mailman-2.1.9.orig/cron/gate_news	2009-04-17 02:41:00.000000000 +0200
+++ mailman-2.1.9/cron/gate_news	2009-04-17 02:41:11.000000000 +0200
@@ -171,6 +171,7 @@
                     msg['X-Originally-To'] = msg['To']
                     del msg['To']
                 msg['To'] = mlist.GetListEmail()
+                del msg['Newsgroups']
                 # Post the message to the locked list
                 inq = get_switchboard(mm_cfg.INQUEUE_DIR)
                 inq.enqueue(msg,
Index: mailman-2.1.9/Mailman/Queue/NewsRunner.py
===================================================================
--- mailman-2.1.9.orig/Mailman/Queue/NewsRunner.py	2009-04-17 02:39:54.000000000 +0200
+++ mailman-2.1.9/Mailman/Queue/NewsRunner.py	2009-04-17 02:41:11.000000000 +0200
@@ -59,6 +59,8 @@
     def _dispose(self, mlist, msg, msgdata):
         # Make sure we have the most up-to-date state
         mlist.Load()
+        if msg['X-Mailman-ID']:
+            return False
         if not msgdata.get('prepped'):
             prepare_message(mlist, msg, msgdata)
         try:
@@ -143,8 +145,7 @@
             if lname == mlist.internal_name() and hname == mlist.host_name:
                 hackmsgid = False
     if hackmsgid:
-        del msg['message-id']
-        msg['Message-ID'] = Utils.unique_message_id(mlist)
+        msg['X-Mailman-ID'] = Utils.unique_message_id(mlist)
     # Lines: is useful
     if msg['Lines'] is None:
         # BAW: is there a better way?


Hier ist eine sauberere Variante das obigen Patches, welche allerdings noch nicht getestet wurde. Das Messgae-ID-verhalten ist jetzt konfigurierbar und standardmäßig wie im orignalen Mailman eingestellt:

Index: mailman-2.1.9/Mailman/Queue/NewsRunner.py
===================================================================
--- mailman-2.1.9.orig/Mailman/Queue/NewsRunner.py	2009-04-17 05:18:00.000000000 +0200
+++ mailman-2.1.9/Mailman/Queue/NewsRunner.py	2009-04-19 12:04:35.000000000 +0200
 -59,6 +59,13 @@
     def _dispose(self, mlist, msg, msgdata):
         # Make sure we have the most up-to-date state
         mlist.Load()
+        if not mm_cfg.NNTP_MANGLE_MSGID:
+            xtrace = msg['x-mailman-nntp-trace']
+            xlstid = mlist.internal_name() + '@' + mlist.host_name
+            if xtrace:
+                for xid in re.split('\s*,\s*', xtrace):
+                    if xid == xlstid:
+                        return False
         if not msgdata.get('prepped'):
             prepare_message(mlist, msg, msgdata)
         try:
 -134,17 +141,27 @@
     # looping.
     #
     # Our Message-ID format is <mailman.secs.pid.listname@hostname>
-    msgid = msg['message-id']
-    hackmsgid = True
-    if msgid:
-        mo = mcre.search(msgid)
-        if mo:
-            lname, hname = mo.group('listname', 'hostname')
-            if lname == mlist.internal_name() and hname == mlist.host_name:
-                hackmsgid = False
-    if hackmsgid:
-        del msg['message-id']
-        msg['Message-ID'] = Utils.unique_message_id(mlist)
+    if mm_cfg.NNTP_MANGLE_MSGID == True:
+        msgid = msg['message-id']
+        hackmsgid = True
+        if msgid:
+            mo = mcre.search(msgid)
+            if mo:
+                lname, hname = mo.group('listname', 'hostname')
+                if lname == mlist.internal_name() and hname == mlist.host_name:
+                    hackmsgid = False
+        if hackmsgid:
+            del msg['message-id']
+            msg['Message-ID'] = Utils.unique_message_id(mlist)
+    else:
+        xtrace = msg['x-mailman-nntp-trace']
+        xlstid = mlist.internal_name() + '@' + mlist.host_name
+        del msg['x-mailman-nntp-trace']
+        if xtrace:
+            msg['X-Mailman-NNTP-Trace'] = xtrace + ', ' + xlstid
+        else:
+            msg['X-Mailman-NNTP-Trace'] = xlstid
+
     # Lines: is useful
     if msg['Lines'] is None:
         # BAW: is there a better way?
Index: mailman-2.1.9/Mailman/Defaults.py.in
===================================================================
--- mailman-2.1.9.orig/Mailman/Defaults.py.in	2009-04-19 11:42:00.000000000 +0200
+++ mailman-2.1.9/Mailman/Defaults.py.in	2009-04-19 11:45:42.000000000 +0200
 -459,6 +459,14 @@
     ('mime-version', 'X-MIME-Version'),
     ]
 
+# The following parameter specifies whether NNTP message ids are mangled
+# when received from the newsgroup and pushed to the list. If mangling is
+# enabled, mailman will exchange the original id with a mailman-id. This
+# usually leads to broken threading in newsgroups. If mangling is disabled,
+# Mailman will keep the original id but add a X-Mailman-NNTP-Trace header
+# to keep track of duplicates.
+NNTP_MANGLE_MSGID = Yes
+
 # All `normal' messages which are delivered to the entire list membership go
 # through this pipeline of handler modules.  Lists themselves can override the
 # global pipeline by defining a `pipeline' attribute.