Archiwa tagu: exim

Weryfikacja nadawcy maila część 2.

Założenie: chcemy pozwolić aby użytkownik, który przeszedł autoryzację, mógł wysłać maila z polem „From:” zawierającym jego główny adres mailowy lub alias prowadzący do bazowego konta.

Opis z poprzedniego wpisu załatwiał nam część do momentu „lub alias”.  Czyli mieliśmy tak:

deny

authenticated  = *
condition      = ${if eq {$authenticated_id}{${lc:$sender_address}}{no}{yes}}
message         = rejected: Nieprawidłowy nadawca.

Czyli potrzebujemy rozbudować to o warunek sprawdzający czy adres nadawcy jest aliasem do użytkownika, którym użytkownik się zautoryzował. Zaimplementowanie tego jest mocno uzależnione od sposobu przechowywania tych danych w konkretnej instalacji. I różnica powinna sprowadzić się do przepisania warunku w selekcie. Tutaj zapytanie będzie dostosowane do mojej bazy, która jest bardzo podobna do omawianej w innych wpisach na tym blogu. W międzyczasie od napisania poprzedniego artykułu, zmieniłem trochę ten warunek, obecnie wygląda następująco:
condition = ${if or {
{ !eqi{$authenticated_id} {$sender_address}}\
{ !eqi{$authenticated_id} {${address:$header_From:}} }\
}\
}

Czyli mamy tutaj drugi test (dodatkowo sprawdzam nagłówek „From:”) oraz została odwrócona logika warunku. Drobiazg:)

Zdefiniujmy zapytanie do bazy danych zwracające nam wszystkie aliasy dla danego konta. Nie możemy zapomnieć także, że to zapytanie powinno zwrócić także głównego użytkownika!:)
PGSQL_Q_AUTH = SELECT alias FROM aliasy WHERE destination = '${quote_pgsql:$authenticated_id}' UNION SELECT '${quote_pgsql:$authenticated_id}'

Oraz warunek, który sprawdza nadawcę:

!condition = ${if and{\
{forany{<\n ${lookup pgsql {PGSQL_Q_AUTH}}}{eqi{$item}{$sender_address}} }\
{forany{<\n ${lookup pgsql {PGSQL_Q_AUTH}}}{eqi{$item}{${address:$header_From:}}} }\
}\
}

Smacznego!

P.S. Nie mam pojęcia dlaczego tak trudno jest w wordpressie użyć tabulacji do robienia wcięć w tekście. Sprawdzałem jakieś dwie wtyczki, bez pozytywnego rezultatu. I z tego powodu, wpisy eximowe wyglądają okropnie.

Walka z collateral spamem

Z fałszywymi zwrotkami napewno często mieliście doczynienia. Nagle dostajecie wiadomości, że wiadomość nie mogła być dostarczona użytkownikowi np. xxx@kolekcja.mejor.pl , albo dostajecie info o tym, że w mailu był wirus i został odrzucony.

Problem ten wynika z nieprawidłowej konfiguracji serwera. Powinien on jeszcze w czasie sesji sprawdzać czy istnieje odbiorca, czy mail nie spełnia warunków aby zostać zakwalifikowanym jako spam, czy nie zawiera wirusa. Część MTA przyjmuje całęgo maila, potem procmailem dostarcza do skrzynek użytkowników. I wtedy sprawdza czy mail to spma itp. Jeśli tak to generowana jest wtedy zwrotka, tylko nie idzie ona do prawdziwego nadawcy (ponieważ to zombie rozsiewajacy spam), tylko do niewinnego użytkownika.

I do tego dokładają się autorespondery („Jestem na urlopie..”).

Jak można więc wykryć czy zwrotka jest „nasza” czy nie? Na przykład można dodać coś w treści, i sprawdzać jest to zawarte w zwrotce. W eximie jest dostępna mechanizm o nazwie BATV. Wysyłany mail jest wtedy znakowany w taki sposób: envelope-from <prvs=03310137b9=xxx@kolekcja.mejor.pl> . Pojawia się nam fragment „prvs=xxxxxxx=”, jest  to hash generowany na podstawie wybranego hasła oraz bieżącej daty (sygnatura taka jest ważna tylko przez pewien czas). Jeżeli tego fragmentu nie będzie to exim odrzuci zwrotkę oraz poinformuje nas o tym w logu:

rejected after DATA: bounce messages must be returned to a BATV signed address

Zauważyłem niestety i minus korzystania z tego mechanizmu. Bywają odrzucane potwierdzenia przeczytania wiadomości. Generowane poprzez (nie jestem tym zaskoczony) „dużego” Outlooka. Trudno, zysk jest większy niż straty.

A teraz najważniejsze, jak to się konfiguruje.

Na początek musimy w głównej sekcji ustawić sobie hasełko do hasha:

BATVKEY = cosTAJEMNICZEGO

Potrzebujemy dwóch nowych ruterów (przypominam, o tym, że kolejność definicji ruterów ma znaczenie!):

dnslookup_batv:
driver = dnslookup
condition = ${if match_domain{$sender_address_domain}{+local_domains}}
domains = ! +local_domains
transport = external_smtp_batv
ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8

batv_redirect:
driver = redirect
data = ${prvscheck {$local_part@$domain}{BATVKEY}}

Oraz potrzebujemy transportu:

external_smtp_batv:
driver = smtp
return_path = ${prvs {$return_path}{BATVKEY}}

Weryfikacja nadawcy maila część 1.

Podczas dotychczasowych opisów konfiguracji Exima umknęła mi kwestia weryfikacji nadawcy, czy nadawca jest taki sam jak użytkownik, który się zautoryzował poprzez SMTP AUTH. Na tą sytuację zwrócił mi uwagę Adrian H. Dzięki :)

Przykładowo, mamy konto pocztowe zbieram_spam@kolekcja.mejor.pl , w programie pocztowym konfigurujemy w połączenie do serwera SMTP użytkownika zbieram_spam@kolekcja.mejor.pl , natomiast w ustawieniach konta możemy wprowadzić: prezes_firmy@kolekcja.mejor.pl . Czyli w mailu pojawi nam się From:  prezes_firmy@kolekcja.mejor.pl pomimo tego, że nie mamy prawa korzystać z tego konta.

Musimy więc porównać, czy sender, czyli nadawca jest taki sam jak użytkownik, który odmeldował nam się loginem i hasłem. Zatem w acl_check_data (czyli tak naprawdę w acl_smtp_data) , gdzieś blisko początku, dodajemy:

deny     authenticated  = *
condition      = ${if eq {$authenticated_id}{${lc:$sender_address}}{no}{yes}}
message         = rejected: Nie
prawidłowy nadawca.

Tutaj pojawił mi się mały dylemat, pisząc poprzednie teksty, przyjąłem odruchowo, że alias do konta jest aliasem służącym tylko do odbierania poczty. Pisząc obrazowo, jest konto zbieram_spam@kolekcja.mejor.pl do którego zakładamy aliasy: uwielbiam_ICIC@kolekcja.mejor.pl oraz icic_to_miedzynarodowi_spamerzy@kolekcja.mejor.pl

to mail przychodzący pod dowolny w/w adres wyląduję w jednym i tym samym maildirze. Natomiast pocztę można wysyłać jedynie jako zbieram_spam@kolekcja.mejor.pl . Natomiast Adrian zasugerował, że zbieracz_spamu mógłby także chcieć wysłać maila jako icic_to_miedzynarodowi_spamerzy@kolekcja.mejor.pl . A tego powyższy wpis nie dopuszcza.

Jak to zrobić jest w drugiej części.

Jak odrzucić maila i zostawić sobie jednocześnie jego kopię

Ten post będzie o tym jak zapewnić większą ilość raportów wysyłanych przez SpamCopa do abuse@…

Zwykle (czyli tak jak np. ja miałem ;) ) serwer pocztowy jest tak skonfigurowany, że w momencie uznania iż dany mail jest spamem wysyła komunikat 550 i kończy sesję. Może to się stać zarówno podczas testów samego nagłowka, czyli zwykle jest to sprawdzenie poprawności syntaktycznej nagłówka i przede wszystkim odpytanie RBL, jak i po odebraniu całego maila, wtedy system wykrywający spam ( np. Spamassassin ) analizuje jego treść i oznacza go jako ham/spam.

Tak czy inaczej mail taki zostaje odrzucony, my wiemy, że była próba zaproponowania nam viagry ale nie mamy corpus delicti do zaraportowania.

Uważam, że jeśli nadawca siedzi już w RBLu to są dwa powody aby zakończyć konwersację natychmiast, bez przyjmowania całości maila. Pierwszy powód to taki, że skoro jest już na czarnej liście to znaczy, że został już zgłoszony odpowiednią ilość razy. Drugim jest fakt, że po to korzystam z czarnych list aby zmniejszyć obciążenie łącza jak i samego serwera, ciężkim SpamAssasinem. Czyli wybór prosty, jeżeli mail zostanie odrzucony poprzez antyspama to wtedy chciałbym mieć jego kopię do zaraportowania.

Do zaimplementowania tej funkcji w Eximie wykorzystałem fakereject .

Plan działania jest taki: oznaczam takiego maila zmienną, dodaje nowy router, przed routerem, który normalnie doręczył by maila do maildira. W nim sprawdzam stan zmiennej oznaczającej czy dany mail jest spamem czy nie. Jeśli wynik testu jest pozytywny to kieruje przesyłkę do oddzielnego transportu.

O to szczegóły, kolorem czerwonym oznaczam dodatkowe wpisy obok standardowo występujących.

acl_check_data:

……

deny warn message           = This message scored $spam_score spam points.

spam                  = nobody:true
condition         = ${if >{$spam_score_int}{44}{1}{0}}
set acl_m1        = spam
control              = fakereject/This message scored $spam_score spam points.SC.

begin routers

dnslookup:

………

spam_fakereject:

driver = accept
condition = ${if eq {$acl_m1}{spam}{true}{false}}
transport = spam_transport

……..

begin transports

spam_transport:

driver = appendfile
directory = /home/spam
maildir_format
delivery_date_add
envelope_to_add

To zapewni nam, że w katalogu /home/spam wyląduje wszystko ze zbyt wysoką punktacją. Teraż możemy sobie poczytać wszelkie oferty ;) oraz zgłosić je komu trzeba.

Jeżeli chcemy automagicznie, bez czytania, wysłać zgłoszenie do SpamCopa to możemy to zrobić poprzez modyfikację transportu tak aby wołaj od razu spamassassina (za pomocą którego będziemy wysyłać raport).

Skorzystamy z drivera pipe

spam_transport:

driver = pipe
command = /usr/bin/spamassassin -r

Potrzebujemy także uaktywnić wymagany plugin w Spamassassinie.

W pliku v310.pre dodajemy:

loadplugin Mail::SpamAssassin::Plugin::SpamCop

a w pliku local.cf podajemy adres do submitowania przypisany do naszego konta na SC:

spamcop_to_address      submit……@…..

Voila.


Exim i aliasy z bazy postgresowej

Aliasy trzymam w bardzo prostej tabelce:

CREATE TABLE aliasy
(
id serial NOT NULL,
alias text NOT NULL DEFAULT ”::text,
destination text NOT NULL DEFAULT ”::text,
CONSTRAINT aliasy_pkey PRIMARY KEY (id)
);

CREATE UNIQUE INDEX ind_alias
ON aliasy
USING btree
(alias);

CREATE TRIGGER cleanup_aliases
BEFORE INSERT OR UPDATE
ON aliasy
FOR EACH ROW
EXECUTE PROCEDURE cleanup_aliases();

CREATE OR REPLACE FUNCTION cleanup_aliases()
RETURNS „trigger” AS
$BODY$
DECLARE
BEGIN
NEW.alias := trim(both FROM lower(NEW.alias));
NEW.destination := trim(both FROM lower(NEW.destination));
RETURN NEW;
END;
$BODY$
LANGUAGE 'plpgsql’ VOLATILE;

Do tego jest trigger mający na celu zapisać w bazie dane małymi literami z obciętymi spacjami na początku oraz końcu. Ten trigger jest zapożyczony z blogu depesza.

Sam ruter w eximie wygląda następująco:

aliasy_postgres:
driver = redirect
allow_fail
allow_defer
data = ${lookup pgsql{ SELECT destination FROM aliasy where alias = (’${quote_pgsql:$local_part}@${quote_pgsql:$domain}’) }}

Exim + postgresql

Nadeszła chwila, kiedy to unixowe konta nie wystarczają do obsługi poczty. Witajcie wirtualni userzy.

Dlaczego postgres? Ponieważ bardzo nie lubię mysqla.

Podczas migracji korzystałem z różnych opisów dostępnych w sieci, wiele informacji (oraz trigerów :)  ) zaczerpnąłem ze strony depesza oraz ze strony Baseciqa . Okazało się jednak, że w powyższych opisach,  oraz w wielu innych jakie google podsuwały, brakowało kilku kluczowych elementów aby exim działał tak jak powinien działać serwer pocztowy. Tym „drobiazgiem” była przede wszystkim nieomówiona autoryzacja użytkowników wysyłających pocztę. Silnie podpierając się stroną ( http://devel.reinikainen.net/attachments/Exim/configure ) uruchomiłem możliwość wysyłania poczty wirtualnym użytkownikom.

Uff, następuje pierwsza próba wysłania maila. I zonk. Okazuje się, że exim dokleja swój primary hostname do adresu mailowego nadawcy. Czyli miałem nadawce takiego:

„user@wirtualna.domena.tld@moj.komputer.tld”

Tutaj wszystko zamykało się w jednej linijce:

control       = submission/sender_retain

Kolejna próba.. I? Pełny sukces! Zadziałało!

Kolejnym etapem będzie uruchomienie aliasów.