inn+suck - instalacja.

Rafał Czeczótka, michu@amg.gda.pl

v2.02, 1 listopad 1998


Tekst ten opisuje procedurę instalacji lokalnego serwera news (inn), sposób wymiany postów (suck) oraz metodę kompresji newsów w drodze (ssh). Oryginał tego dokumentu można znaleźć na stronie www.amg.gda.pl/~michu/linux.html. Zostało użyte kodowanie ISO-8859-2.

1. Wstęp.

1.1 Przedmowa.

Całą treść tego dokumentu stanowi opis mojej instalacji duetu suck+inn w systemie RedHat5.1, w oparciu o konkretne pakiety (inn-1.7.2-13 i suck-3.9.4-2). Impulsem do napisania tego tekstu były moje początkowo nieudane próby instalacji oraz nikły odzew na moje posty na grupie pl.comp.os.linux (pewnie jak zwykle moje zapytania zaginęły gdzieś w potoku informacji i zapytań docierających tu codziennie). Nie mam zamiaru pretendować do miana fachowca od konfiguracji serwerów news (po prostu u mnie już to działa), tym nie mniej mam nadzieję, że opis minimalnej, działającej konfiguracji będzie dla kogoś przydatny.

Wszelkie sugestie i poprawki są mile widziane i należy je wysyłać pod adres michu@amg.gda.pl.

W tym dokumencie w paru miejscach porównuję inn'a do leafnode'a, którego wcześniej używałem.

1.2 Podziękowania.

Następujący ludzie przyczynili się do postania tego dokumentu, taką czy inną drogą, świadomie lub nieświadomie (w kolejności alfabetycznej):

2. Słowo o programach, instalacja i konfiguracja.

2.1 Co to jest inn i suck.

Inn jest to "InterNetNews daemon" czyli program umożliwiający wielu użytkownikom korzystanie z zasobów news.

Suck jest to zasysacz newsów; pośredniczy on w wymianie newsów pomiędzy dwoma serwerami: naszym i zdalnym (emulując zachowanie normalnego czytnika; protokół wymiany postów pomiędzy serwerami (wbudowany w inn'a) odbywa się na trochę innej zasadzie i wymaga specjalnej konfiguracji po obu stronach, czego chcemy uniknąć).

2.2 Kiedy instalować inn+suck.

Jeśli uważasz, że spełnione są poniższe warunki:

  1. Nudzi Ci się i potrzebujesz jakiejś odmiany (warunek konieczny, bo przecież tak naprawdę jeśli potrzebujesz lokalnego serwera newsów, to z pewnością wystarczy Ci dużo prostszy w konfiguracji i używaniu leafnode, poza tym ten eksperyment może Cię kosztować sporo czasu i nadszarpniętych nerwów),
  2. Z newsów na twoim komputerze korzysta więcej niż jeden użytkownik (bo dla jednego usera zupełnie wystarczające jest "rtin -SQ") ewentualnie "twój" komputer służy jako serwer news dla całej sieci (np. w firmie),
  3. Możliwości leafnode'a już Ci nie wystarczają (potrzebujesz killfile'i, różnych ograniczeń na ściąganą pocztę newsową, ...),
  4. Ściąganie newsów trwa u Ciebie zbyt długo i potrzebujesz ich kompresji,

to znaczy, że powinieneś zainstalować duet inn+suck.

Jeśli już będziesz chciał zainstalować to oprogramowanie, to będą Ci potrzebne następujące (lub inne wersje) pakiety:

  1. cleanfeed (np. cleanfeed-0.95.5a-1),
  2. inn (np. inn-1.7.2-13, UWAGA: oryginalny pakiet z dystrybucji RH5.1 jest niepoprawny),
  3. perl-MD5 (np. perl-MD5-1.7-2),
  4. suck (np. suck-3.9.4-2).

Ja skorzystałem z niżej wymienionych adresów:

2.3 Wady i zalety tego rozwiązania.

Zalety inn+suck:

  1. Szybki (piekielnie),
  2. Znaczne możliwości (killfile, ...), choć tu należy raczej patrzeć na możliwości suck'a (ponieważ dopiero po ściągnięciu pliki są przesyłane do inn'a a jak coś już w całości przeszło przez modem, to moim zdaniem niech już zostanie),
  3. Można tak skonfigurować inn+suck, że newsy są ściągane skompresowane, czyli czas transmisji można skrócić parokrotnie,
  4. Można grep'ować pliki z zawartością grup bez żadnych "skutków ubocznych" (ta uwaga odnosi się do dużo prostszego leafnode'a, gdzie czas do expire jest liczony od daty ostatniego dostępu do pliku, więc jeśli "to się zrobiło", to czas ten oczywiście przedłużał się),
  5. Instalując ten serwer jesteś "wśród najlepszych" (większość dużych serwerów news działa właśnie na inn'ie).

Wady inn+suck:

  1. Dość pogmatwana konfiguracja i hermetyczna dokumentacja (przynajmniej na początek) ale ten dokument powstał właśnie aby wyeliminować tę niedogodność,
  2. Pamięciożerność:

2.4 Instalacja i konfiguracja.

Proces instalacji i "konfiguracji" jest prosty (przynajmniej do pierwszego "ruszenia", ale o tym, bez tego wstępu, przeciętny zjadacz newsów możne przekonać się dopiero po parodniowych dociekaniach):

  1. Zainstalować inn i suck (i jeszcze parę wymienionych wcześniej drobiazgów),
  2. W pliku "/etc/news/innfeed.conf" usunąć sekcję peers,
  3. W pliku "/etc/news/newsfeeds" dodać własną sekcję z feeds, tj.:
    ----- ciach -----
    ...
    news.task.gda.pl\
            :!junk,!test,!to\
            :Tf,Wnm:
    ...
    ----- ciach -----
    
    gdzie news.task.gda.pl to nazwa mojego serwera news, oraz do definicji dystrybucji akceptowanych przez nasz serwer dodać polską:
    ----- ciach -----
    ...
    ME\
        :*,@alt.binaries.warez.*,!junk,!control*,!local*,!foo.*\
        /pl,world,usa,na,gnu,bionet,pubnet,u3b,eunet,vmsnet,inet,ddn,k12\
        ::
    ##   ^^ - to jest to pl
    ...
    ----- ciach -----
    
  4. W pliku "/usr/lib/suck/get.news.innxmit" wstawić nazwę serwera news (REMOTE_HOST=news.task.gda.pl) oraz "sajtu" (tego samego co w punkcie 3., tj. SITE=news.task.gda.pl),
  5. W suck'u w pliku "/usr/lib/suck/sucknewsrc" zapisać wszystkie interesujące nas grupy i numery postów, od których ma się zacząć "ściąganie", np.:
    ----- ciach -----
    ...
    pl.comp.ogonki 1
    pl.comp.os.linux 1
    ...
    ----- ciach -----
    
    UWAGA!!! Zaczynając od pierwszego postu jesteśmy narażeni na ściąganie dużej ilości danych a co się z tym wiąże znaczne koszty. W końcu i tak zapewne okaże się, że większość postów jest za stara i zostanie odrzucona przez inn'a. Lepiej więc nie zaczynać od początku ale od kilku(set) postów wstecz. U mnie 57 grup (w całości) z dostępem online (ethernet "wpięty do" TASKu, transfer osiągał 160KB/sec, jednak to było bardziej ograniczenie zdalnego serwera niż łącza) ściągało się prawie godzinę,
  6. Usunąć pliki "/etc/cron.daily/inn-cron-rnews" oraz "/etc/cron.hourly/inn-cron-nntpsend" (ich funkcje przejmuje suck),
  7. Teraz możemy już wystartować serwer np. poleceniem "/etc/rc.d/init.d/innd start". Można/trzeba także dodać odpowiednie linki do katalogów "/etc/rc.d/rc0-6].d/" (np. poleceniem ntsysv),
  8. Dodać grupy do inn'a. Można to zrobić ręcznie poleceniem "ctlinnd newgroup nazwa.grupy" lub skorzystać z poniższego skryptu:
    ----- ciach -----
    #!/bin/bash
    #
    # Ten skrypt tworzy automatycznie grupy w inn-ie, ktore podales w pliku
    # /usr/lib/suck/sucknewsrc - konfiguracyjnym dla suck-a.
    # UWAGA !!!
    # Wymagany format tego pliku to:
    ############################
    # nazwa.grupy numer.artykulu
    ############################
    #
    # Mozesz podac inna lokalizacje
    SUCK_FILE=/usr/lib/suck/sucknewsrc
    #
    # Podaj sciezke do programu ctlinnd. Skrypt sprobuje sam zgadnac, ale
    # lepiej podaj jak wiesz.
    CTLINND=`which ctlinnd`
    
    cat ${SUCK_FILE} | while read ln; do
            set -e $ln >/dev/null
            ${CTLINND} newgroup $1
            if [ $? -eq 1 ]; then
                    echo Blad podczas zakladania grupy $1 !!!
                    exit
            fi
    done
    ----- ciach -----
    
  9. Aby nie ściągać grup "control", "junk", "test" ani "to" (z pewnością nam się nie przydadzą), musimy stworzyć plik "/usr/lib/suck/active-ignore":
    ----- ciach -----
    control
    junk
    test
    to
    ----- ciach -----
    
    Oczywiście grup tych nie należy umieszczać w pliku "/usr/lib/suck/sucknewsrc",
  10. Wymianę newsów ze zdalnym serwerem inicjujemy skryptem "/usr/lib/suck/get.news.innxmit".

2.5 Kompresja newsów w drodze.

Ponieważ newsy są danymi tekstowymi, więc ich kompresja zdecydowanie skraca czas transmisji, dzięki czemu z pewnością zaoszczędzimy trochę pieniędzy kosztem naszego operatora telekomunikacyjnego (pieniądze te mogą być wysłane do autora powyższego tekstu, za ewentualne straty autor oczywiście nie bierze żadnej odpowiedzialności ;-). Osobiście wydaje mi się, że przedstawione tu rozwiązanie jest najbardziej naturalne i elastyczne. Nie oznacza to oczywiście, że nie można tego zrobić lepiej. Podczas eksperymentów okazało się także, że zwykłe tunelowanie komunikacji w skompresowanym kanale ssh nie daje oczekiwanych rezultatów, stąd wyniknęła potrzeba wywołania suck'a na zdalnym komputerze (po prostu komunikacja pomiędzy komputerami jest na tyle duża, że po uwzględnieniu opóżnień występujących w trakcie transferu, niemal całkowicie niweczony jest efekt zmniejszonej objętości danych).

Opisując poniższe rozwiązanie zakładam, że masz już poprawnie zainstalowane i skonfigurowane pakiety inn+suck. Aby z niego korzystać niezbędne nam także będą:

  1. na domowym komputerze musi być zainstalowny klient ssh,
  2. musimy mieć dostęp do konta na zdalny komputerze z zainstalowanym systemem Unix'opodobnym, podłączony w miarę szybkim łączem stałym do internetu, z zainstalowanym suck'iem oraz uruchomionym demonem ssh.

Pakiety ssh w wersji międzynarodowej (te z literką "i" na końcu) można ściągnąć z ftp.task.gda.pl/pub/linux/redhat-crypto/i386/. Podczas pisania tego dokumentu najnowszymi wersjami były: ssh-1.2.26-1i, ssh-clients-1.2.26-1i, ssh-extras-1.2.26-1i i ssh-server-1.2.26-1i.

Cała przedstawiona poniżej idea opiera się na możliwości uruchomienia suck'a na zdalnym komputerze tak, aby wiadomości były wysyłane w postaci strumienia danych, który jest przesyłany w skompresowanym kanale ssh (opcja "-C"). Dopiero później, lokalnie, za pomocą skryptu filter2rnews, strumień ten jest dzielony na poszczególne wiadomości, które są wpuszczane za pomocą programu rnews do lokalnego serwera innd.

W tym celu musimy:

  1. Usunąć z pliku "/usr/lib/suck/get.news.innx" całą sekcję służącą do wysyłania wiadomości, czyli skrypt ten powinien być postaci:
    ----- ciach -----
    #!/bin/sh
    
    #BEFORE USING - check to ensure all the paths defined below are
    #               correct!!
    
    #NOTE: this script probably needs to be run by root.  Most systems
    # will not let a normal user run ctlinnd 
    
    REMOTE_HOST=news.task.gda.pl
    LOCAL_HOST=localhost
    
    SPOOLDIR=/var/spool/news  # base directory for articles to be rposted
    NEWSDIR=/usr/lib/news     # base directory for news binaries 
    BASEDIR=/usr/lib/suck     # base directory for scripts and data files
    
    CTLINND=${NEWSDIR}/bin/ctlinnd    # location of binary
    SHLOCK=${NEWSDIR}/bin/shlock      # location of binary
    
    TMPDIR=${BASEDIR}           # location for suck.* files
    MSGDIR=${BASEDIR}/Msgs      # where to put MultiFile messages when
                                #   getting them
    
    SITE=news.task.gda.pl       # name of site from newsfeeds file
    
    OUTGOING=${SPOOLDIR}/out.going/${SITE}  # location of the list of
                                            #   articles to upload
    OUTGOINGNEW=${OUTGOING}.new # file to contain the list temporarily
    OUTGOINGFAIL=${OUTGOINGNEW}.fail  # file with failed xfers
    SCRIPT=${BASEDIR}/put.news  # my filter for rpost
    OUTFILE=/tmp/tmp$$          # used by rpost as article after it is
                                #   filtered
    LOCKFILE=${BASEDIR}/getnews.lock  # lock file to prevent multiple
                                      #   instances of script
    NEWSGROUP=news              # which group owns the file in out.going,
                                #   typically either news or uucp.
    
    TESTHOST=testhost
    RPOST=rpost
    SUCK=suck
    
    # if we are already running, abort 
    
    trap 'rm -f ${LOCKFILE} ; echo "Aborting" ; exit 1' 1 2 3 15
    ${SHLOCK} -p $$ -f ${LOCKFILE}
    if [ $? -ne 0 ]; then
      echo "Already running, can't run two at one time"
      exit
    fi
    
    # now upload messages
    if [ -s ${OUTGOING}  -o -s ${OUTGOINGNEW} ]; then
      ${TESTHOST} ${REMOTE_HOST} -s
    
      if [ $? -ne 0 ]; then
        echo "Remote posting host not responding"
      else
        if [ ! -s ${OUTGOINGNEW} ]; then
          mv ${OUTGOING} ${OUTGOINGNEW}
          ${CTLINND} flush ${SITE}
        fi
    
        # outgoing messages to post
        ${RPOST} ${REMOTE_HOST} -d -b ${OUTGOINGNEW} -p ${SPOOLDIR} \
            -f \$\$o=${OUTFILE} ${SCRIPT} \$\$i ${OUTFILE}
        ERRLEV=$?
    
        if [ ${ERRLEV} -eq 0 ]; then
          echo "Remotely posted articles"
          rm ${OUTFILE}
        elif [ ${ERRLEV} -eq 1 ]; then
          echo "Error posting a message"
        elif [ ${ERRLEV} -eq 2 ]; then
          echo "Unable to do NNTP authorization with remote server"
        elif [ ${ERRLEV} -eq 3 ]; then
          echo "Unexpected answer from remote server to a command"
          echo "while doing NNTP authorization"
        elif [ ${ERRLEV} -eq -1 ]; then
          echo "Fatal error"
        fi
    
        if [ -f ${OUTGOINGFAIL} ]; then
          mv ${OUTGOINGFAIL} ${OUTGOINGNEW} # so we can re do it
          chown news.${NEWSGROUP} ${OUTGOINGNEW}
          chmod 664 ${OUTGOINGNEW}
        fi
      fi
    fi      
    
    rm -f ${LOCKFILE}
    ----- ciach -----
    
    Oczywiście należy pamiętać o właściwym ustawieniu zmiennych REMOTE_HOST i SITE.
  2. Skopiować z lokalnego katalogu "/usr/lib/suck/" pliki "active-ignore", "suck.killlog", "suckkillfile" oraz "sucknewsrc" do zdalnego katalogu "$HOME/suck/" (jeśli nie jest tam zainstalowany suck, a tamta maszyna ma taką samą architekturę jak nasza, to możemy skopiować tam także program "/usr/bin/suck").
  3. Stworzyć możliwość logowania się na zdalnym komputerze za pomocą ssh bez użycia hasła (tylko na podstawie znajomości klucza RSA):
    1. wygenerować parę kluczy RSA komendą ssh-keygen (w pass phrase nie podawać hasła),
    2. następnie skopiwać plik "$HOME/.ssh/identity.pub" na zdalny komputer do pliku "$HOME/.ssh/authorized_keys".
    UWAGA!!! Należy zdawać sobie sprawę z tego, że mimo, iż takie rozwiązanie jest o wiele bezpieczniejsze od logowania się za pomocą hasła, to krytyczną rolę dla bezpieczeństwa odgrywa tutaj nie ujawnianie zawartości pliku "$HOME/.ssh/identity", czyli prywatnej połowy klucza. Istnieje także rozwiązanie umożliwiające wygenerowanie klucza z hasłem i podawanie go tylko raz na sesję (patrz program ssh-agent).
  4. Utworzyć skrypt "/usr/local/bin/filter2rnews":
    ----- ciach -----
    #!/usr/bin/perl -w
    
    while (not eof(STDIN)) {
        @POST = "";
        do {
            $linia = <>;
            push @POST, $linia if $linia !~ /^\.$/;
        } until ($linia =~ /^\.$/);
        $dlug = length(join('',@POST));
        print "#! rnews $dlug\n";
        print @POST;
    }
    ----- ciach -----
    
  5. Po dokonaniu wszystkich powyższych kroków możemy już pobierać newsy komendą:
    ----- ciach -----
    ssh -C -l username serwer.name \
      '~/suck/suck news.task.gda.pl -dd ~/suck -dt ~/suck -M -c' | \
      filter2rnews | rnews -N -vvv -S localhost
    ----- ciach -----
    
    gdzie username to nazwa użytkownika na komputerze serwer.name a news.task.gda.pl jest nazwą naszego serwera news. Wiadomości wysyłamy tak jak poprzednio, czyli za pomocą skryptu "/usr/lib/suck/get.news.innxmit".

2.6 Uwagi i kruczki.

  1. Usuwanie grup odbywa się przez "ctlinnd rmgroup nazwa.grupy" (jeśli wywołujemy suck'a lokalnie, to on sam usunie taką grupę z pliku sucknewsrc, jeśli zdalnie (patrz kompresja) to musimy to zrobić ręcznie),
    UWAGA!!! Nie należy usuwać grup "control", "junk", "test" ani "to", inn bardzo źle to znosi.
  2. Opisy grup można dodawać w pliku "/var/lib/news/newsgroups", np.:
    ----- ciach -----
    ...
    pl.comp.ogonki O polskich literkach w komputerach.
    pl.comp.os.linux Linux - system operacyjny dla kazdego.
    ...
    ----- ciach -----
    
  3. Dane o przeterminowaniach są w pliku "/etc/news/expire.ctl", usuwanie przeterminowanych postów można wymusić uruchamiając skrypt "/etc/cron.daily/inn-cron-expire" (przecież nie każdy ma włączony komputer całą dobę).
  4. Wyłączenie odrzucania artykułów przez innd (już to przecież robi suck) dokonuje się komendą "ctlinnd perl n".
  5. Aby usunąć limit linii dla postów ściągniętych przez inn'a (już po zaakceptowaniu przez suck'a) należy dodać w pliku "/etc/rc.d/rc.news" do opcji FLAGS flagę "-l0".
  6. Jeśli podczas ściągania newsów pojawi się komunikat "GROUP command not recognized, try the -M option" oczywiście dodaj w pliku "/usr/lib/suck/get.news.innxmit" opcję "-M" do wywołania suck'a.
  7. Od czasu do czasu można wyczyścić skrytkę pocztową użytkownika news np. z konta root'a komendą "su - news -c pine".
  8. W pliku "/etc/news/inn.conf" możemy zmienić parametry "organization" (bo napis "A poorly-installed InterNetNews site" w postach wygląda nieelegancko) oraz ustawić "pathhost" (ułatwia czytanie logów).
  9. Sprawdzenie kolejki postów wychodzących można dokonać poniższym skryptem (jest to przerobiony skrypt newsq z pakietu leafnode):
    ----- ciach -----
    #!/usr/bin/perl
    
    $spooldir = "/var/spool/news";
    
    if ( chdir "$spooldir/out.going" && opendir( DIR, "." ) ) {
        @sites = readdir( DIR );
        closedir( DIR );
    
        foreach (@sites) {
            if ( open(F, "< $_") ) {
                while(<F>) { 
                    push @posts, (split)[0];
                }
                close F;
            }
        }
    
        undef $/;
        foreach (@posts) {
            if ( open(F, "< $spooldir/$_") ) {
                undef $subject, $newsgroups, $from;
                $_ = <F>;
                close F;
                s/\n\n.*//s;
                s/\r//gs;
                s/\n\s+/ /sg;
                foreach ( split( /\n/, $_ ) ) {
                    $subject = $1 if ( /^Subject:\s+(.*)/i );
                    $newsgroups = $1 if ( /^Newsgroups:\s+(.*)/i );
                    $from = $1 if ( /^From:\s+(.*)/i );
                }
                print $from, " in ", $newsgroups, "\n\t", $subject, "\n", 
                    if ( $subject ne "" && $from ne "" && $newsgroups ne "" );
            }
        }
    }
    ----- ciach -----
    
  10. Jeśli suck odsyła ściągnięte posty z powrotem do zdalnego serwera, to możemy zmienić sekcję feeds w pliku "/etc/news/newsfeeds" w następujący sposób:
    ----- ciach -----
    ...
    news.task.gda.pl/news.task.gda.pl\
            :!junk,!test,!to\
            :Tf,Wnm:
    ...
    ----- ciach -----
    
    UWAGA!!! Nie jestem przekonany do tego rozwiązania, ale podobno działa (w każdym razie komuś taki wpis rozwiązał problem).
  11. Jeśli zobaczymy na ekranie napis typu:
    ----- ciach -----
    ...
    stdin: rejected 437 Unwanted newsgroup "pl.rec.radio" [Path:\
    news.task.gda.pl!orion.cst.tpsa.pl...]
    ...
    ----- ciach -----
    
    nie należy wpadać w panikę. Najprawdopodobniej jest to wynik błędu w zdalnym inn'ie (wersja 2.1) związanego z bazami overview.

3. Prawa autorskie/legalność.

Prawa autorskie należą do (C) Rafała Czeczótki michu@amg.gda.pl. Dokument ten jest rozpowszechniany na podstawie GPL (Gnu Public License).

Znaki towarowe należą do ich właścicieli. Nie ma żadnych gwarancji co do dokładności czy przydatności informacji zawartych w tym dokumencie.