Pagina 1 di 1

Auto-ban per utenti in canali presenti in lista-nera

Inviato: 19/02/2010, 21:20
da BuDuS
Il problema:
Eseguire BAN+KICK automatico degli utenti che, quando entrano nel canale, risultano essere presenti in uno o più canali elencati in una "blacklist" (file $HOME/.xchat2/buduscript/badchannel.txt)

Soluzione da inserire all'interno di "botconnetct.mcr" (ATTENZIONE: dalla prossima release del BOT (11.6) questa funzionalità sarà già inclusa e andrà tolta da "botconnect.mcr"):

Codice: Seleziona tutto

/ECHO %C8,1Aggiunge la gestione dei BADCHANNEL.
/event add 0 spcl_badchannel * /budus set buduscript_bot_badchannel_joined_list _NONE_\;/budus if "'$(grep -F \( 319 \) "$HOME/$mxchat_path/buduscript/$hostname.log" | grep -F \( $ru :\) | grep -F \($channel \) | tail -n1 | sed \(s@.* :@@\))'" ! '' /budus set buduscript_bot_badchannel_joined_list $output\;/budus InsertCommandInQueue() /budus cmd /budus pipe_script for chan_join in $(cat "$HOME/$mxchat_path/buduscript/badchannel.txt") ; do find_channel=$(echo \($buduscript_bot_badchannel_joined_list\) | grep -F "${chan_join} ") ; if test "${find_channel}" != "" ; then echo \(/budus sendsess $server/$channel /budus ban + *!*@$domain init( $buduscript_bot_badchannel_ban_time,3600 ) $ru\); echo "/budus sendsess $server/$channel /KICK $ru Non sono graditi gli utenti di ${chan_join}"; fi; done
/event add 0 jchannel '$nick'!'$ru' /whois $ru\;/budus InsertCommandInQueueTimed() 3 /budus sendsess $server/$channel /event event spcl_badchannel $event_params

Spiegazione: come al solito, se non si scompone i comandi, difficilmente si può capire qualcosa, perché "per ragioni tecniche", siamo obbligati a creare le cose con "comandi" che, necessariamente, devono contenere tutto il necessario.

Parto dalla sentinella più semplice:

Codice: Seleziona tutto

/event add 0 jchannel '$nick'!'$ru' /whois $ru\;/budus InsertCommandInQueueTimed() 3 /budus sendsess $server/$channel /event event spcl_badchannel $event_params

Tradotta significa:
Aggiungi una sentinella (add) che ogni volta (0) che entra un utente (jchannel) con nickname ($ru) diverso da quello dell'utente locale ($nick) esegui questi 2 comandi:
  • Codice: Seleziona tutto

    /whois $ru

    Direi che il comando si commenta da solo: esegui il "whois" dell'utente che è appena entrato ($ru).
  • Codice: Seleziona tutto

    /budus InsertCommandInQueueTimed() 3 /budus sendsess $server/$channel /event event spcl_badchannel $event_params

    Significato: Inserisci un comando nella "coda dei comandi" in modo temporizzato, con un ritardo di 3 secondi. Il comando inserito:

    Codice: Seleziona tutto

    /budus sendsess $server/$channel /event event spcl_badchanne $event_params

    significa: invia alla sessione che ha generato l'evento, la generazione di un evento di tipo "spcl_badchannel" con i parametri standard ($event_params).

In sintesi: la sentinella ha il compito di fare il "whois" degli utenti che entrano e di invocare una seconda sentinella (quella più corposa e che risponde all'evento "spcl_badchannel").
Ora passo alla seconda sentinella:

Codice: Seleziona tutto

/event add 0 spcl_badchannel * /budus set buduscript_bot_badchannel_joined_list _NONE_\;/budus if "'$(grep -F \( 319 \) "$HOME/$mxchat_path/buduscript/$hostname.log" | grep -F \( $ru :\) | grep -F \($channel \) | tail -n1 | sed \(s@.* :@@\))'" ! '' /budus set buduscript_bot_badchannel_joined_list $output\;/budus InsertCommandInQueue() /budus cmd /budus pipe_script for chan_join in $(cat "$HOME/$mxchat_path/buduscript/badchannel.txt") ; do find_channel=$(echo \($buduscript_bot_badchannel_joined_list\) | grep -F "${chan_join} ") ; if test "${find_channel}" != "" ; then echo \(/budus sendsess $server/$channel /budus ban + *!*@$domain init( $buduscript_bot_badchannel_ban_time,3600 ) $ru\); echo "/budus sendsess $server/$channel /KICK $ru Non sono graditi gli utenti di ${chan_join}"; fi; done

Questa sentinella reagisce all'evento "spcl_badchannel" (che quindi è speciale e "va generato") e, non avendo condizione (*), esegue sempre i suoi comandi.
Partiamo dal primo comando che viene eseguito:

Codice: Seleziona tutto

/budus set buduscript_bot_badchannel_joined_list _NONE_

Qui viene creata o comunque re-inizializzata la variabile "buduscript_bot_badchannel_joined_list" al valore "_NONE_".
Questa variabile ha il compito di contenere la lista dei canali che l'utente appena entrato risulta essere presente.
Il secondo comando:

Codice: Seleziona tutto

/budus if "'$(grep -F \( 319 \) "$HOME/$mxchat_path/buduscript/$hostname.log" | grep -F \( $ru :\) | grep -F \($channel \) | tail -n1 | sed \(s@.* :@@\))'" ! '' /budus set buduscript_bot_badchannel_joined_list $output

è una condizione abbastanza complicata.
Sinteticamente serve per verificare se il "whois" è stato eseguito e, in caso affermativo, estrapolare la lista dei canali che l'utente che ha effettuato il join risulta essere presente, per poi andarli a memorizzare nella variabile "buduscript_bot_badchannel_joined_list".
Per fare tutto questo, procede in questo modo:
  • Esegue il seguente comando (quello compreso in "$(...)") in un terminale fittizio del sistema operativo:

    Codice: Seleziona tutto

    grep -F \( 319 \) "$HOME/$mxchat_path/buduscript/$hostname.log" | grep -F \( $ru :\) | grep -F \($channel \) | tail -n1 | sed \(s@.* :@@\)

    Per essere precisi, il comando non viene eseguito esattamente così, perché prima viene "risolto"; supponendo che l'utente si chiami "pippo", il canale "#buduscript" e il network "irc.budus.net", la risoluzione è la seguente:

    Codice: Seleziona tutto

    grep -F ' 319 ' "$HOME/.xchat2/buduscript/irc.budus.net.log" | grep -F ' pippo :' | grep -F '#buduscript ' | tail -n1 | sed 's@.* :@@'

    N.B.: Le sequenze "\(" e "\)" vengono opportunamente sostituite da apici. Si usa questo sistema perché se una variabile contiene un apice, la protezione del parametro deve rispettarlo; ad esempio, se una variabile "$prova" ha valore "prova'variabile" per proteggerla dobbiamo scrivere "\($prova\)" in modo che, quando risolta, il sistema userà: 'prova'\''variabile'

    Il comando invoca dei comandi del sistema operativo utilizzando la "pipe" (carattere "|"); ovvero:
    • Cerca (grep) il testo (-F) "spazio319spazio" (in linea di massima rimarranno solo i messaggi del server che appartengono al codice "319", cioè i "WHOIS") all'interno del file "$HOME/.xchat2/buduscript/irc.budus.net.log"
    • quindi l'output filtralo (grep) lasciando solo le righe che contengono il testo (-F) "spaziopippospazio:"
    • quindi filtra ulteriormente (grep) lasciando le righe che contengono il testo (-F) "#buduscriptspazio"
    • tieni solo l'ultima riga (tail -n1)
    • e di quest'ultima togli tutto quello che viene prima di "spazio:" (sed 's@.* :@@').
    E' praticamente un filtro che lavora sul file di log che contiene il risultato del WHOIS e ne estrapola "la lista dei canali".
  • Mette il risultato ottenuto nella variabile "$output" e verifica se: '$output' diverso da ''
  • Se la condizione è vera esegue il comando:

    Codice: Seleziona tutto

    /budus set buduscript_bot_badchannel_joined_list $output

    il cui significato è: metti il risultato ottenuto dal comando descritto sopra (che ora è contenuto in "$output") nella variabile "buduscript_bot_badchannel_joined_list"
Ora che ha immagazzinato i canali nei quali l'utente risulta presente, procede con il secondo comando:

Codice: Seleziona tutto

/budus InsertCommandInQueue() /budus cmd /budus pipe_script for chan_join in $(cat "$HOME/$mxchat_path/buduscript/badchannel.txt") ; do find_channel=$(echo \($buduscript_bot_badchannel_joined_list\) | grep -F "${chan_join} ") ; if test "${find_channel}" != "" ; then echo \(/budus sendsess $server/$channel /budus ban + *!*@$domain init( $buduscript_bot_badchannel_ban_time,3600 ) $ru\); echo "/budus sendsess $server/$channel /KICK $ru Non sono graditi gli utenti di ${chan_join}"; fi; done

Sì, mi rendo conto che anche questo non è banale :roll:
Ma, scomponendolo, non è neanche poi così terribile, anzi, proviamo a dividerlo su più righe (dopo aver risolto alcune cose), in modo che prenda un altro aspetto:

Codice: Seleziona tutto

/budus InsertCommandInQueue()
>/budus cmd
>>/budus pipe_script
>>>for chan_join in $(cat "$HOME/.xchat2/buduscript/badchannel.txt") ; do
>>>>find_channel=$(echo '$buduscript_bot_badchannel_joined_list' | grep -F "${chan_join} ") ;
>>>>if test "${find_channel}" != "" ; then
>>>>>echo '/budus sendsess $server/$channel /budus ban + *!*@$domain init( $buduscript_bot_badchannel_ban_time,3600 ) $ru';
>>>>>echo "/budus sendsess $server/$channel /KICK $ru Non sono graditi gli utenti di ${chan_join}";
>>>>fi;
>>>done

Bene, analizziamo una riga alla volta, dandole un significato:
  • Inserisci il comando nella coda dei comandi

    Codice: Seleziona tutto

    /budus InsertCommandInQueue()
  • Esegui un comando risolvendo variabili utente, funzioni avanzate, ecc... :

    Codice: Seleziona tutto

    /budus cmd
  • Esegui un comando del sistema operativo, catturane l'output ed utilizzalo come fosse un qualcosa che scrive l'utente:

    Codice: Seleziona tutto

    /budus pipe_script
  • Esegui il seguente comando del sistema operativo (quindi, quelli che seguono, sono comandi BASH, non X-Chat):

    Codice: Seleziona tutto

    for chan_join in $(cat "$HOME/.xchat2/buduscript/badchannel.txt") ; do

    che significa: ogni riga contenuta nel file "$HOME/.xchat2/buduscript/badchannel.txt" (il comando cat serve per stampare il contenuto del file specificato) mettila nella variabile "${chan_join}" ed esegui quello che viene dopo, fino al "done".
  • Cerca, nella lista contenente i canali che l'utente è presente (la variabile "$buduscript_bot_badchannel_joined_list'" viene risolta prima che il comando venga eseguito), se è presente il testo (grep -F) "#nomecanalespazio", dove "#nomecanale" è il valore della variabile "${chan_join}" che viene ciclicamente (for) cambiato, e vallo a mettere nella variabile "${find_channel}".

    Codice: Seleziona tutto

    find_channel=$(echo '$buduscript_bot_badchannel_joined_list' | grep -F "${chan_join} ") ;
  • Se la variabile "${find_channel}" non risulta vuota, allora ...

    Codice: Seleziona tutto

    if test "${find_channel}" != "" ; then
  • Stampa (echo) quello che poi verrà interpretato come un comando dello script:

    Codice: Seleziona tutto

    echo '/budus sendsess $server/$channel /budus ban + *!*@$domain init( $buduscript_bot_badchannel_ban_time,3600 ) $ru';

    N.B.: Il comando che viene eseguito non è banalissimo, vale la pena fare alcune considerazioni:
    • Il comando che viene eseguito per primo è "/budus sendsess $server/$channel " e serve per eseguire il comando successivo in una sessione ben determinata.
    • Il comando "/budus ban" serve per eseguire il BAN di un utente sfruttandone alcuni dati; nel nostro caso il BAN utilizzerà il dominio ("*!*@$domain").
    • Se la variabile "$buduscript_bot_badchannel_ban_time" non è stata creata/inizializzata precedentemente, tramite la funzione avanzata "init( nomevariabile,valore) la si crea e inizializza al valore "3600". Questo valore determina "quando il BAN dovrà essere tolto". E' possibile personalizzare questo valore inizializzando (in "botconnect.mcr") la variabile, ad esempio:

      Codice: Seleziona tutto

      /budus set buduscript_bot_badchannel_ban_time 1800

      ridurrebbe a 30min il BAN.
    • La variabile "$ru" contiene il nickname dell'utente da bannare.
  • Stampa (echo) quello che poi verrà interpretato come un comando dello script:

    Codice: Seleziona tutto

    echo "/budus sendsess $server/$channel /KICK $ru Non sono graditi gli utenti di ${chan_join}";

    visto quanto scritto sopra, direi che qui dovrebbe essere abbastanza chiaro cosa avviene; in sintesi: avviene il KICK dell'utente.
Sintetizzando: per ogni canale che risulta bannato, verifica se l'utente ne è ospitato e, se ciò si avvera, esegue un BAN e poi un KICK di quest'ultimo.

Ho cercato di risolvere il problema senza ricorrere ad un file script (.sh) esterno, ma solo con l'uso di sentinelle e, laddove non era possibile diversamente, qualche comando del sistema operativo.

In pratica, affinché il sistema funzioni, sarà necessario elencare nel file "badchannel.txt" i canali che si intende "bannare"; quando un utente effettua il join, viene verificato in quali canali è presente e controllato se uno di questi combacia con quelli "bannati".

E' chiaro che, se un utente entra prima nel nostro canale e poi in uno di quelli "proibiti", il sistema non funziona.
Se proprio non gestite canali particolarmente affollati, forse è affrontabile un "controllo periodico" che, ad esempio, operi sugli utenti che non hanno nessuna modalità. Per fare questo è sufficiente ricorrere ad una "funzione avanzata" come la "exec( filter,command )" (vedere: "/budus help function") che viene periodicamente invocata (vedere: "/HELP TIMER").

NUOVA VERSIONE

Inviato: 04/03/2010, 22:09
da BuDuS
A partire dalla versione 3.2.00 di BuDuScRiPt è possibile risolvere il problema in modo analogo ma più efficiente: anziché catturare la lista dei canali - nei quali è presente l'utente che effettua il join - dal file di LOG, la si preleva direttamente dalla risposta del WHOIS, quando questa arriva.

Questo, oltre a consentire tempi di risposta più rapidi (non si deve utilizzare comandi temporizzati), garantisce che il sistema funzioni anche in caso di forte lag e comunque risulta più "leggero" perché non fa uso di chiamate al sistema operativo.

Le sentinelle sono sempre 2, simili a quelle descritte in precedenza:

Codice: Seleziona tutto

/event add 0 jchannel '$nick'!'$ru' /budus set buduscript_bot_badchannel_joined_list _NONE_\;/event add ? other '$channel:$server$_319$_$lu$_$ru$_:='$channel^data' /event event spcl_badchannel $event_params\;/whois $ru
/event add 0 spcl_badchannel * /budus cmd /budus set buduscript_bot_badchannel_joined_list search(  :,$data )\;/budus cmd /budus pipe_script for chan_join in $(cat "$HOME/$mxchat_path/buduscript/badchannel.txt") ; do find_channel=$(echo \($buduscript_bot_badchannel_joined_list\) | grep -F "${chan_join} ") ; if test "${find_channel}" != "" ; then echo \(/budus sendsess $server/$channel /budus ban + *!*@$domain init( $buduscript_bot_badchannel_ban_time,3600 ) $ru\); echo "/budus sendsess $server/$channel /KICK $ru Non sono graditi gli utenti di ${chan_join}"; fi; done

Come in precedenza, viene intercettato il "JCHANNEL" degli utenti diversi da quello locale ma, in questo caso, viene subito inizializzata la variabile "$buduscript_bot_badchannel_joined_list" (usata per immagazzinare la lista dei canali "joinati") e aggiunta la sentinella che ha il compito di controllare il risultato del WHOIS:

Codice: Seleziona tutto

/event add ? other '$channel:$server$_319$_$lu$_$ru$_:='$channel^data' /event event spcl_badchannel $event_params

La CONDIZIONE della sentinella:

Codice: Seleziona tutto

'$channel:$server$_319$_$lu$_$ru$_:='$channel^data'

è comprensibile solo se risolta; supponendo che "$channel" sia "#miocanale", "$server" sia "irc.budus.org", "$lu" sia "BuDuS" e "$ru" sia "Paperino" otteniamo:

Codice: Seleziona tutto

'#miocanale:irc.budus.org 319 BuDuS Paperino :='#miocanale$data'

Notare che "^data" è diventato "$data". La variabile "$data" conterrà i dati del "WHOIS" e sarà soddisfatta solo quando viene individuato il messaggio codificato " 319 ", richiesto dall'utente "BuDuS", per l'utente "Pippo" e sul server "irc.budus.org".
Il nome del canale viene usato nella CONDIZIONE sia nella COSTANTE che nella VARIABILE; questo serve perché, se l'utente esegue il join contemporaneo di più canali, devono essere create più sentinelle con scopo identico ma dalla forma diversa, altrimenti solo una effettivamente verrebbe inserita e avrebbe la possibilità di reagire (in altri termini: potrebbe verificarsi che l'utente viene cacciato da un solo canale e non tutti quelli nei quali ha effettuato join).

quindi, effettuato il WHOIS dell'utente che ha effettuato il join:

Codice: Seleziona tutto

/whois $ru

Quando si ricevono i dati del "WHOIS", la sentinella esposta sopra reagisce generando l'evento "spcl_badchannel", il quale è gestito dalla seconda sentinella:

Codice: Seleziona tutto

/event add 0 spcl_badchannel * /budus cmd /budus set buduscript_bot_badchannel_joined_list search(  :,$data )\;/budus cmd /budus pipe_script for chan_join in $(cat "$HOME/$mxchat_path/buduscript/badchannel.txt") ; do find_channel=$(echo \($buduscript_bot_badchannel_joined_list\) | grep -F "${chan_join} ") ; if test "${find_channel}" != "" ; then echo \(/budus sendsess $server/$channel /budus ban + *!*@$domain init( $buduscript_bot_badchannel_ban_time,3600 ) $ru\); echo "/budus sendsess $server/$channel /KICK $ru Non sono graditi gli utenti di ${chan_join}"; fi; done

Dato che una parte - quella finale - di questa sentinella è identica a quella descritta nel post precedente, analizziamo solo il comando che la rende diversa:

Codice: Seleziona tutto

/budus cmd /budus set buduscript_bot_badchannel_joined_list search(  :,$data )

Lo scopo di questo comando è quello di estrapolare dalla variabile "$data" la lista dei canali ritornata dal "WHOIS" ed immagazzinarla nella variabile "$buduscript_bot_badchannel_joined_list".