Biuletyn nr 25

Biuletyn KDM
1 | 2 | 3 | 4 | 5
6 | 7 | 8 | 9 | 10
11 | 12 | 13 | 14
15 | 16 | 17 | 18
19 | 20 | 21 | 22
23 | 24 | 25 | 26
27 | 28 | 29 | 30
31 | 32
Lista biuletynów

Biuletyn nr 25 (22 listopada 2007)


Spis treści

Sposoby walki ze spamem

Autor: Rafał Maszkowski

Spam najpierw pojawił się w Usenecie. Jedne z pierwszych przypadków to reklama biura adwokackiego załatwiającego amerykańskie "zielone karty" oraz "Global Alert For All: Jesus is Coming Soon". Początkowo takie wybryki śmieszyły. Sam pomysł wysłania tego rodzaju tekstów np. do grupy comp.lang.c prowokował do zabawnych komentarzy. Jednak po kolejnych kilku spamach przestało być śmiesznie, zrobiło się nudno a dyskusje w grupach trudno było kontynuować. Na szczęście scentralizowany charakter Usenetu ułatwił kasowanie spamu. Działa w tej chwili wiele automatów analizujących artykuły w poszukiwaniu nadmiernej liczby podobnych i kasujących je. W momencie, kiedy spam, zwykle natychmiast kasowany, osiągnął połowę liczby artykułów usenetowych było oczywiste, że podobną tylko trudniejszą walkę trzeba będzie stoczyć o pocztę żeby nie dopuścić do jej zniszczenia jako medium komunikacji.

Poczta była szczególnie łatwym celem. Dziś już niewielka część użytkowników Internetu pamięta czasy, kiedy każdy komputer był open relayem, tzn. można było przez niego przesłać list skądkolwiek dokądkolwiek. Używało się do tego adresów w specjalnej notacji. Na początku lat 90-tych trudno było sobie wyobrazić, że ktoś tę użyteczną czasem właściwość serwerów pocztowych będzie chciał wykorzystać do rozsyłania milionów listów z bezsensownymi informacjami.

Obecnie spam stanowi również większość przesyłek przesyłanych pocztą elektroniczną. W Sieci trwa nieustanne zmaganie chciwych szaleńców, którzy starają się zapychać nasze skrzynki reklamami, z administratorami, którzy próbują do tego nie dopuścić. Typowy spammer zbiera adresy z WWW albo kupuje zestaw takich adresów i uruchamia program spamujący, zwykle też kupiony od kogoś, kto takie programy pisze. Spammer musi działać szybko i wykorzystać optymalnie konto, z którego nadaje, zanim zostanie zamknięte przez firmę, która mu je udostępniła, co czasem dzieje się w ciągu minut, chociaż zdarzają się też firmy internetowe wspierające działalność spammerów albo nie starające się im jej utrudnić. Program generuje kolejne listy, zwykle doklejając części losowe, które mają zmylić filtry, w tym adres nadawcy. Prawie zawsze podejmowana jest tylko jedna próba wysłania każdego listu. Spamming jest obecnie zredukowany do działalności partyzanckiej i zwykle warunki pozwalają tylko na jednorazowe ostrzelanie nas, ofiar spamu, a nie pozwalają na długotrwałe oblężenie i strzelanie do skutku. Specjalny rodzaj spamu rozsyłają wirusy. Korzystają one z systemów mało odpornych na wirusy, niekoniecznie nawet dlatego, że mają wiele błędów, ale z powodu błędów projektowych albo złego ustawienia przez producenta domyślnych uprawnień. Opinię dobrze przystosowanego do powielania wirusów ma system MS Windows. Za to w praktyce nie występują wirusy działające na Uniksie, poza historycznym już robakiem internetowym z 1988 r. Wirus, po dostaniu się do systemu, generuje listy tak jak inne programy spamujące, wykorzystując jako adresy zarówno odbiorców jak i nadawców, adresy znalezione w spisach adresowych.

Technik obrony przez takimi atakami jest bardzo wiele. Najłatwiej jest się bronić przed spamem generowanym przez wirusy. W spamie przesyłają one również sam program generujący spamy. W ICM-ie do wykrywania wirusów używamy programu clamav (wołany przez MIMEDefanga). Listy z wirusami są zatrzymywane tylko jeżeli użytkownik zgłosi chęć filtracji swojej poczty.

Zwykłe spamy, bez wirusów, jest trudniej łapać, ale wystarczy na nie spojrzeć żeby zauważyć, że odróżniają się od prawdziwych listów. Komputerowi jest trudniej tak po prostu na nie spojrzeć, ale rolę automatu do oceny listów spełnia program SpamAssassin (wołany przez MIMEDefanga), który przydziela punkty według starannie wybranych kryteriów oraz może uczyć swój wewnętrzny filtr bayesowski co jest spamem a co nie. Może to robić automatycznie, uwzględniając punktację, która wskazuje, że list prawie na pewno jest spamem albo prawie na pewno nie jest, albo przez dodanie do swojej bazy danych podanych przez administratora próbek spamu (czyli tej ohydnej mielonki) i hamu (czyli pysznej szynki - opcja wegeteriańska nie jest uwzględniona). Odebrany przez użytkownika, mimo filtru, spam do nakarmienia SpamAssasina można dostarczać e-mailem na adres spam-learn@icm.edu.pl .

Nawet bez włączania w konfiguracji użytkownika odrzucania spamu przez SpamAssasina (od 5 punktów) można korzystać z jego usług. Poczta sprawdzana pod kątem wirusów jest zawsze dodatkowo oznaczana przez SpamAssasina i można ją sortować przy pomocy procmaila (w ICM-ie nie jest potrzebne wpisywanie niczego do .forward).

Bardzo skutecznie filtruje spam greylisting. Jest to metoda, której skuteczność na początku zaskakuje, ale ma ona swoje uzasadnienie. Greylisting polega na odrzuceniu pierwszej próby przysłania listu i odpowiedzeniu nadawcy informacji "spróbuj później". Okazuje się, że w ponad 90% przypadków nadawcy spamu nigdy nie próbują przysłać tego samego listu drugi raz. Żeby spammerowi nie było za łatwo zakaz jest utrzymywany przez pewien krótki czas (w ICM-ie przez 1 minutę), za to kolejny list od danego nadawcy, z danego serwera do danego odbiorcy nie jest już przez greylisting zatrzymywany. Jeżeli ktoś przysyła listy z tego samego serwera na ten sam adres jakiejś osoby w ICM-ie nie rzadziej niż co 92 dni, to greylisting nie będzie zatrzymywał jego listów. Ta prosta metoda wykorzystuje problemy spammerów z wysyłką bardzo wielu listów w bardzo krótkim czasie oraz partyzancki tryb ich działalności i redukuje ilość spamu o rząd wielkości. Wadą jest niewielkie dodatkowe opóźnienie listów, a czasem zwiększenie częstotliwości ujawniania błędnych konfiguracji serwerów, które np. powtarzają listy zbyt rzadko. W ICM-ie filtr ten jest pierwszym, na który natyka się list i domyślnie jest u wszystkich włączony.

Inny rodzaj filtrów to czarne listy - spisy maszyn, które są open relayami albo z których często dochodzi spam. Ta metoda ma teraz mniejsze znaczenie niż jeszcze kilka lat temu i nie używamy jej w ICM-ie intensywnie. Domyślna konfiguracja użytkowników to brak filtracji poczty tą metodą.

Pytania dotyczące filtracji spamu jak też problemów z pocztą w ICM-ie można zgłaszać do mnie (rzm@icm.edu.pl) albo do lan@icm.edu.pl

Wywoływanie procedur języka Fortran z poziomu języka C - przykład

Autor: Maciek Cytowski

Czasem stajemy przed następującym problemem:

Piszę program w C (bo lubię ten język). Chcę skorzystać z biblioteki, która jest całkowicie napisana w Fortranie.

Dobra wiadomość jest taka, że nie musimy przepisywać całego naszego kodu do języka Fortran. Wystarczy, że poprawnie wywołamy funkcję biblioteczną i dolinkujemy interesującą nas bibliotekę. Sztukę tą zaprezentuję na przykładzie użycia biblioteki LAPACK służącej do rozwiązywania zagadnień z szerokiej dziedziny algebry liniowej.

Wywołanie procedury

Aby wywołać dowolną procedurę musimy po pierwsze znać jej nazwę. Po drugie musimy wiedzieć jak ją wywołać (parametry). Po trzecie musimy umieć nasz program skompilować. Przeanalizujmy poniższy przykład:

Napisaliśmy w języku Fortran poniższy fragment kodu obliczający sumę dwóch liczb:

SUBROUTINE SUM(A,B,C)
INTEGER A,B,C
C=A+B
END

Kompilujemy go np. tak:

g77 -c sum.f

Chcemy teraz wywołać procedurę sum(a,b,c) z wewnątrz kodu napisanego w języku C. Możemy to zrobić tak:

extern sum_(int *a,int *b,int *c);

int main()
{
        int a,b,c;

        a=2;
        b=2;

        sum_(&a,&b,&c);

        printf("Wynik dodawania: %d\n",c);

        return 0;
}

Powyższy program kompilujemy i linkujemy z binarką sum.o w następujący sposób:

gcc -o program main.c sum.o -lg2c


Osoba nie zaznajomiona z powyższą techniką zapewne zauważyła, że wykonaliśmy tutaj kilka magicznych kroków. Po pierwsze na początku naszego kodu w języku C użyliśmy słówka extern do zadeklarowania naszej procedury. Po drugie typy parametrów tej procedury są delikatnie mówiąc "dziwne". Po trzecie sama procedura nazywa się sum_, a nie sum (dołączony został dodatkowy znak podkreślenia). Po czwarte przy linkowaniu dołączyliśmy bibliotekę g2c.

Wszystkie te wątpliwości spróbujemy sobie zaraz wyjaśnić.

Słówko extern

Używając słówka extern informujemy kompilator, że definicja zmiennej bądź procedury używanej w programie znajduje się w innym pliku źródłowym bądź bibliotece na zewnątrz. Podczas kompilacji kompilator zezwoli nam na odwoływanie się do takiego obiektu, ufając nam, że dołączymy brakującą definicję w procesie linkowania. Jeśli tego nie zrobimy to kompilator najpewniej obrazi się na nas zwracając błąd podobny do następującego:

main.c:(.text+0x23): undefined reference to `sum_'


Typy parametrów

Jak można się domyślać przy wywoływaniu procedur napisanych w Fortranie musimy dokonać pewnego rodzaju mapowania typów pomiędzy C a Fortranem. Podstawowe różnice związane są oczywiście z różnym nazewnictwem poszczególnych typów. Liczbę typu całkowitego w Fortranie nazwiemy integer, natomiast w C poprostu int. Druga różnica związana jest ze sposobem przekazywania argumentów do funkcji. Gdy w Fortranie wywołujemy funkcję, np.:

call sum(a,b,c)

to przekazujemy jej właściwy adres podawanych argumentów (w C nazwalibyśmy to wskaźnikiem). W języku C wywołanie:

sum(a,b,c);

przekazuje funkcji sum wartość argumentów a, b, c.

I dlatego właśnie musimy dokonać odpowiedniej konwersji:

integer -> int *
double -> double *
itp..


Nazwy procedur

Oczywiście aby wywołać procedurę Fortranu z poziomu dowolnego języka musimy ją umieć jakoś nazwać. Zwykle nie jest to dokładna nazwa Fortran-owa, lecz odrobinę zmodyfikowana jej wersja. Modyfikacja nazwy jest zależna od systemu i kompilatora, ale zwykle na systemach Unix-o podobnych nazwa ta będzie oryginalną nazwą Fortran-ową pisaną małymi literami z dodanym podkreśleniem, np:

  SUM -> sum_

Aby upewnić się, że dobrze wywołamy funkcję pochodzącą z dowolnej biblioteki wystarczy wykonać następujące polecenie na archiwum tej biblioteki:

nm /usr/lib/liblapack.a

Polecenie to wypisze nam nazwy wszystkich plików obiektowych zapakowanych w tym archiwum oraz wszelkie funkcje, których definicje znajdują się w tych plikach. Polecenia tego możemy również użyć do dowolnego pojedynczego pliku obiektowego:

nm sum.o


Biblioteka g2c

Aby uzyskać pełną kompatybilność z językiem Fortan z poziomu C potrzebne jest jeszcze dolinkowanie biblioteki g2c. Zawiera ona definicję wszelkich funkcji wbudowanych języka Fortran. W naszym powyższym przykładzie z sumą dwóch liczb linkowanie biblioteki g2c nie było konieczne. Nasz program sumował jedynie dwie liczby. Gdyby jednak plik sum.f wyglądał tak:

SUBROUTINE SUM(A,B,C)
INTEGER A,B,C
C=A+B
PRINT*,'Obliczylem sume dwoch liczb'
END

Wówczas próba linkowania bez biblioteki g2c zakończyłaby się niepowodzeniem:

cytron:/home/staff/sheed/% gcc -o program main.c sum.o
sum.o: In function `sum_':
sum.f:(.text+0x31): undefined reference to `s_wsle'
sum.f:(.text+0x4f): undefined reference to `do_lio'
sum.f:(.text+0x59): undefined reference to `e_wsle'
collect2: ld returned 1 exit status
Exit 1

Dla bezpieczeństwa należy zawsze pamiętać, że jeśli nasz program napisany w C używa funkcji Fortran-owych to przy linkowaniu dodajemy bibliotekę g2c.

Przykład

W tym przykładzie zaprezentuję sposób wywoływania procedur wyliczających rozwiązanie układu równań liniowych i pochodzących z pakietu LAPACK (Linear Algebra PACKage). Przy okazji zwrócę również uwagę na kluczową różnicę w przechowywaniu tablic w C oraz Fortranie. Załóżmy, że chcemy rozwiązać następujący układ równań:

Ax=b gdzie

    | 1 2 |
A = | 3 4 |

    | 3 |
b = | 7 |


Rozwiązaniem tego układu jest oczywiście wektor jednostkowy.

Do obliczeń wykorzystamy funkcję dgesv z pakietu LAPACK. Opis jej działania i objaśnienie znaczenia parametrów znajduje się tutaj: http://www.netlib.org/lapack/double/dgesv.f

Korzystając z polecenia nm (np. nm /usr/lib/liblapack.a | grep dgesv) dowiadujemy się, że z poziomu języka C powinniśmy wołać funkcję dgesv_. Konwersja parametrów nie powinna nam sprawić również trudności. W pierwszym podejściu piszemy kod:

extern int dgesv_(int *n, int *nrhs, double *a, int *lda, int *ipiv, double *b, int *ldb, int *info );

int main()
{
        double *A,*b;
        int *ipiv;
        int n=2,nrhs=1;
        int info;

        A=(double*) calloc(n*n,sizeof(double));
        b=(double*) calloc(n,sizeof(double));
        ipiv=(int*) calloc(n,sizeof(int));

        A[0]=1;
        A[1]=2;
        A[2]=3;
        A[3]=4; 

        b[0]=3;
        b[1]=7;

        dgesv_(&n,&nrhs,A,&n,ipiv,b,&n,&info);

        printf("x=\n");
        printf("%f\n",b[0]);
        printf("%f\n",b[1]);

        return 0;

}

Po kompilacji:

gcc -o lap_ex lap_ex.c -llapack -lg2c -lpthread

i uruchomieniu:

cytron:/home/staff/sheed/% ./lap_ex
x=
4.500000
-0.500000

widzimy, że wynik jest błędny.

Natrafiliśmy tutaj na bardzo istotną różnicę pomiędzy Fortranem a C - różnicę w sposobie "układania" w pamięci tablic. W języku C układane są w kolejności wierszowej (1szy wierszy, 2gi wiersz,...). W Fortranie kolejność układania tablic w pamięci jest kolumnowa (1sza kolumna, 2ga kolumna, ...). Dla przykładu tablica A(2,2) jest w Fortranie przechowywana tak:

A(1,1)   A(2,1)   A(1,2)   A(2,2)

a tablica A[2][2] jest w C przechowywana tak:

A[1][1]  A[1][2]  A[2][1]  A[2][2]

W związku z tym widać, że musimy "przekonwertować" zapis naszej tablicy przed wywołaniem funkcji dgesv. Oto gotowe prawidłowe rozwiązanie:

extern int dgesv_(int *n, int *nrhs, double *a, int *lda, int *ipiv, double *b, int *ldb, int *info );

int main()
{
        double *A,*b;
        int *ipiv;
        int n=2,nrhs=1;
        int info;

        A=(double*) calloc(n*n,sizeof(double));
        b=(double*) calloc(n,sizeof(double));
        ipiv=(int*) calloc(n,sizeof(int));

        A[0]=1;
        A[1]=3;
        A[2]=2;
        A[3]=4;

        b[0]=3;
        b[1]=7; 

        dgesv_(&n,&nrhs,A,&n,ipiv,b,&n,&info);

        printf("x=\n");
        printf("%f\n",b[0]);
        printf("%f\n",b[1]);

        return 0;

}

Zapowiedź

Nie chcąc obrazić zwolenników języka Fortran zobowiązuję się napisać drugą część tego instruktażu, czyli "Jak to zrobić w drugą stronę?", czyli "Wywoływanie procedur języka C z poziomu języka Fortran".

Nowa Lista TOP 500

Autor: Maciek Cytowski

Tegoroczna listopadowa lista TOP 500 została ogłoszona na konferencji Supercomputing 07, która odbyła się w Reno (USA).

Sc07.jpg
Widok na halę wystawienniczą w Reno (fot. M.Remiszewski)


Warto przyjrzeć się jej bliżej, gdyż zaszło na niej kilka ciekawych zmian. Oto sama czołówka, czyli lista największych:


Pozycja Lokalizacja Komputer Liczba procesorów Max wydajność [TFlops/s]
1 DOE/NNSA/LLNL

USA

- Blue Gene/L - eServer Blue Gene Solution

IBM

212992 478,2
2 Forschungszentrum Juelich (FZJ)

Niemcy

JUGENE - Blue Gene/P Solution

IBM

65536 167,3
3 SGI/New Mexico Computing Applications Center (NMCAC)

USA

SGI Altix ICE 8200, Xeon quad core 3.0 GHz

IBM

14336 126,9
4 Computational Research Laboratories, TATA SONS

Indie

EKA - Cluster Platform 3000 BL460c, Xeon 53xx 3GHz, Infiniband

HP

14240 117,9
5 Government Agency

Szwecja

Cluster Platform 3000 BL460c, Xeon 53xx 2.66GHz, Infiniband

HP

13728 102,8
6 NNSA/Sandia National Laboratories

USA

Red Storm - Sandia/ Cray Red Storm, Opteron 2.4 GHz dual core

Cray Inc.

26569 102,2
7 Oak Ridge National Laboratory

USA

Jaguar - Cray XT4/XT3

Cray Inc.

23016 101,7
8 IBM Thomas J. Watson Research Center

USA

BGW - eServer Blue Gene Solution

IBM

40960 91,2
9 NERSC/LBNL

USA

Franklin - Cray XT4, 2.6 GHz

Cray Inc.

19320 85,3
10 Stony Brook/BNL, New York Center for Computational Sciences

USA

New York Blue - eServer Blue Gene Solution

IBM

36864 82,1


Statystyki

Bez zmian liderem listy TOP500 jest firma IBM, która ma najmocniejszą instalację na liście, najwięcej instalacji w pierwszej dziesiątce oraz ponad 46% instalacji na całej liście. Zaraz za nią jest firma HP - ponad 33% udziału w liście. Z pośród pozostałych należy wyróżnić Dell (4.8%), SGI (4.4%) oraz Cray Inc. (2.8%). Najwięcej systemów TOP500 zainstalowanych jest w USA (56.6%), Wielkiej Brytanii (9.6%) i w Niemczech (6.2%). Na liście w tym roku pojawiła się jedna instalacja z Polski pochodząca z firmy telekomunikacyjnej i zajmująca 428 miejsce (BladeCenter HS21 Cluster, Xeon dual core, 3 GHz, GigEthernet).

Ciekawe pozycje

Wymienię tutaj kilka pozycji z listy TOP 500, które moim zdaniem są interesujące:

  • 1 miejsce - Komputer z prawie 213 tys. procesorów - pełna dominacja
  • 2 miejsce - Komputer JUGENE w Centrum Komputerowym w Juelich - Niemcy wysoko!
  • 3 miejsce - Nowe Centrum komputerowe w USA - od razu tak wysoko
  • 5 miejsce - Klaster firmy HP ze szwedzkiej agencji rządowej - zastosowania obronne
  • 70 miejsce - Komputer Hitachi z Japonii - 128 procesorów
  • 428 miejsce - "Polski" komputer