Archivi tag: linux

dnsmasq ed Ubuntu: configurare un server DNS/DHCP per ambienti SOHO

Premesso che per mettere in piedi un nameserver locale si possono utilizzare diverse soluzioni open source, anche di tipo enterprise (una su tutte è rappresentata da bind/named), ho deciso di installare dnsmasq su un server Ubuntu per 2 motivi:

1) la rete aveva dimensioni estremamente ridotte (un server, qualche workstation e 3 stampanti), quindi rientrava nell’ambito delle infrastrutture SOHO (Small Office Home Office);

2) vi era la necessità di tirar su anche un servizio di DHCP, configurabile direttamente sull’applicativo in questione (che quindi può svolgere, contemporaneamente, sia il ruolo di nameserver che quello di DHCP server).

dnsmasq

Configurazione del DHCP server

Fare in modo che dnsmasq svolga le funzioni tipiche di un server DHCP è un’operazione abbastanza banale. Infatti, è sufficiente editare la configurazione del demone in questione (operando sul file /etc/dnsmasq.conf), aggiungendo le seguenti direttive:

no-dhcp-interface=eth1

dhcp-range=eth1,192.168.0.100,192.168.0.199,8h

In particolare, ho messo in ascolto il server DHCP sulla sola interfaccia eth0 (dato che si tratta di una macchina dual homed, in cui la scheda eth1 è collegata ad Internet mediante uno screened router). Inoltre, ho definito il pool di indirizzi che possono assere assegnati ai client che ne fanno richiesta, con relativo lease time (8h).

Configurazione del nameserver

Tale configurazione è un po’ più complessa rispetto alla precedente ma risulta comunque abbordabile.

Diciamo che dnsmasq è un nameserver “giocattolo”, in cui molti record DNS devono essere definiti all’interno di un file “piatto”, quale, ad esempio, /etc/hosts (anche se è possibile definire un file ad hoc per tale scopo), senza che vi sia quindi la necessità di creare una specifica zona DNS (cosa che invece risulta essere mandatoria con altri nameserver “un po’ più seri”).

I record di tipo A presenti nel file /etc/hosts avevano un formato simile al seguente:

192.168.0.2     proxy
192.168.0.4     server1
192.168.0.5     PC1
192.168.0.6     stampante1
192.168.0.7     stampante2
192.168.0.9     stampante3
192.168.0.10    PC2

Per quanto riguarda, invece, la configurazione del servizio DNS, ho abilitato le seguenti direttive (all’interno del file /etc/dnsmasq.conf):

interface=eth0
except-interface=eth1
listen-address=192.168.0.2

expand-hosts

domain=soho.loc

Le prime 3 servono a mettere in ascolto il server solo ed esclusivamente sull’interfaccia rivolta verso la LAN. Con expand-hosts e domain=soho.loc, invece,  ho fatto in modo che le query DNS vadano a buon fine anche nel caso in cui venga fornito il solo hostname della macchina di cui si vuole conoscere l’indirizzo IP.

Poichè il suddetto nameserver deve risolvere solo ed esclusivamente gli indirizzi locali, ho dovuto definire i forwarder (o nameserver di upstream) a cui inviare le query per tutte le zone DNS pubbliche. La direttive che ho utilizzato sono le seguenti:

resolv-file=/etc/resolv.dnsmasq
strict-order

dove il contenuto del file /etc/resolv.dnsmasq era il seguente:

nameserver 8.8.8.8
nameserver 208.67.222.222
nameserver 8.8.4.4
nameserver 208.67.220.220

La direttiva strict-order faceva in modo che i forwarder venissero contattati seguendo  l’ordine con cui sono stati definiti all’interno del suddetto file (il secondo nameserver viene contattato solo nel caso in cui il primo non sia raggiungibile, ergo, per ottenere una maggiore ridondanza, ho deciso di alternare ai nameserver di Google quelli di OpenDNS).

Per avere un maggiore controllo sulle query inoltrate al nameserver locale, ho deciso di loggarle su un apposito file di testo grazie ai seguenti parametri di configurazione:

log-queries
log-facility=/var/log/dnsmasq/query.log

Ho anche configurato la rotazione dei log mediante il file dnsmasq posto all’interno della directory /etc/logrotate.d:

/var/log/dnsmasq/query.log {
        rotate 7
        weekly
        compress
        missingok
        notifempty
}

Infine, affinchè i client della LAN riuscissero a “riconoscere” i record DNSSEC (garantendo loro una maggiore sicurezza durante la navigazione su Internet), ho fatto in modo che dnsmasq girasse le query DNSSEC ai forwarder (demandando loro il ruolo di validator).

La direttiva che mi ha consentito di fare ciò è la seguente:

proxy-dnssec

Il fatto che il nameserver primario di Google (8.8.8.8) sia il primo della lista dei forwarder non è certamente un caso. Infatti, esso garantisce dei tempi di risposta più brevi rispetto a quelli di OpenDNS, oltre ad essere anche DNSSEC compliant (cosa che OpenDNS non è).

In definitiva, la configurazione di dnsmasq (in base alle mie esigenze) si è rivelata essere la seguente:

no-dhcp-interface=eth1

dhcp-range=eth1,192.168.0.100,192.168.0.199,8h

interface=eth0
except-interface=eth1
listen-address=192.168.0.2

expand-hosts

domain=soho.loc

resolv-file=/etc/resolv.dnsmasq
strict-order

log-queries
log-facility=/var/log/dnsmasq/query.log

proxy-dnssec

Dopo aver effettuato un controllo sintattico della suddetta configurazione mediante il comando:

root@ubuntubox:~# dnsmasq --test

ed aver riavviato il demone:

root@ubuntubox:~# service dnsmasq restart

sono passato ai test funzionali mediante dig. Per prima cosa ho effettuato una query di tipo A per il record proxy, utilizzando dapprima il solo hostname:

root@fw-scar:~# dig @localhost proxy

; <<>> DiG 9.8.1-P1 <<>> @localhost proxy
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 3216
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;proxy.                         IN      A

;; ANSWER SECTION:
proxy.                  0       IN      A       192.168.0.2

;; Query time: 1 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Fri May 20 15:50:11 2016
;; MSG SIZE  rcvd: 39

e successivamente l’intero FQDN:

 root@fw-scar:~# dig @localhost proxy.soho.loc

; <<>> DiG 9.8.1-P1 <<>> @localhost proxy.soho.loc
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30251
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;proxy.soho.loc.                        IN      A

;; ANSWER SECTION:
proxy.soho.loc.         0       IN      A       192.168.0.2

;; Query time: 1 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Fri May 20 15:52:15 2016
;; MSG SIZE  rcvd: 48

Successivamente mi sono concentrato sui tempi di risposta per i domini pubblici (da parte dei forwarder), ottenendo i seguenti tempi pre-cashing:

root@fw-scar:~# dig @localhost repubblica.it | grep "Query time"
;; Query time: 50 msec

e post caching:

root@fw-scar:~# dig @localhost repubblica.it | grep "Query time"
;; Query time: 0 msec

Infine, ho testato la risoluzione dei record DNSSEC, utilizzando il comando:

root@fw-scar:~# dig @localhost pir.org +dnssec +multi

; <<>> DiG 9.8.1-P1 <<>> @localhost pir.org +dnssec +multi
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 35285
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 512
;; QUESTION SECTION:
;pir.org.               IN A

;; ANSWER SECTION:
pir.org.                299 IN A 97.107.141.235
pir.org.                299 IN RRSIG A 5 2 300 20160602204000 (
                                20160519204000 58424 pir.org.
                                cJwr7HlIMA+DyQ8vqqmkNtHRAqsGVdKWTQkJeP/a5698
                                UTyK/cF08uYhH8xMk9I0RMWqtkJDM8od8hWmYUZgidzi
                                7Fh26m1FQYGAcN/PMw2/6wEnNh4ErWZtXe2fXRAS8btx
                                I+nyRPOCoAHR3CjC0cjKqtniUoWHt5x/51iEBw4= )

;; Query time: 86 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Fri May 20 15:57:36 2016
;; MSG SIZE  rcvd: 219

ricevendo come risposta sia il record A che il relativo RRSIG.

Alla fine della fiera ho messo in piedi un server DNS/DHCP funzionante e funzionale.

Alla prossima.

clean_zombies: script bash per ripulire il sistema dai processi zombie

Tenere sotto controllo il numero di processi attivi sulla nostra macchina è certamente una buona pratica, soprattutto quando si parla di sistemi in produzione. Tale monitoraggio può essere realizzato mediante il buon vecchio Nagios, il quale provvederà ad inviarci un’opportuna notifica nel caso in cui il numero dei processi superi una determinata soglia (definibile a piacere).

bashOccorre precisare, però, che nel computo totale rientrano anche i processi zombie, i quali, per definizione, non possono essere killati (sono già in stato defunct). Ergo, per sbarazzarsene occorrerà “fermare” il processo padre (o parent process). Ora, poichè non esiste pratica più noisa dell’andare a ricercare i padri dei vari processi zombie, ho deciso di realizzare il seguente scrip bash in grado di automatizzare il task in questione (con relativo respawning del parent process):

parents=`ps -ef | grep defunct | grep -v grep | awk '{print $3}' | sort -u | wc -l`

p=1

parentidlist=`ps -ef | grep defunct | grep -v grep | awk '{print $3}' | sort -u`

if [[ ! -z "$parents" ]] && [[ "$parents" -gt 0 ]];then
        while [[ "$p" -le "$parents" ]]
        do
                parentid=`echo $parentidlist | awk -v p="$p" '{print $p}'`
                parentname=`ps -o cmd -p $parentid | grep -v CMD`

                if [[ ! -z "$parentid" ]] && [[ ! -z "$parentname" ]];then
                        echo "Terminating $parentname with PID $parentid..."
                        kill -15 "$parentid"
                        sleep 10
                        running=`ps aux | grep "$parentname" | grep -v grep`
                        if [[ -z "$running" ]];then
                                echo "Starting $parentname..."
                                eval $parentname
                        else
                                echo "Error: the process $parentname is still running, switching to the next one..."
                        fi
                fi

                let p=p+1
        done
else
        echo "No defunct process, exiting..."
        exit 1
fi

Il suddetto codice è abbastanza intuitivo. Per prima cosa individuo il numero totale e la lista dei PPID (parent process id) associati a ciascun processo in stato defunct (se esistono). A questo punto, mediante un banale ciclo while, “termino” i processi padre ricavati in precedenza, con successivo respawning degli stessi (sempre che il kill -15 aka SIGTERM sia andato in buon fine, altrimenti skip e si procede con il PPID successivo). Da notare che ho utilizzato la direttiva eval piuttosto che exec, poichè, in quest’ultimo caso, veniva forzata l’uscita dal while.

Se volete fare qualche test potete utilizzare quest’altro scrip bash (fork_zombies) che ho creato allo scopo:

#!/bin/bash

(sleep 1 & exec /bin/sleep 60)

è sufficiente lanciarne qualche istanza in background mediante il comando:

[root@linuxbox ~]# ./fork_zombies &

Nel prossimo post vedremo come integrare il suddetto scrip con Nagios (sotto forma di event handler).

Alla prossima.

CentOS 6 ed rsyslog: creare un sistema di log centralizzato per i dispositivi di rete

Scenario

Diversi uffici periferici (in gergo branch office), connessi all’ufficio centrale (main office) mediante dei tunnel IPSec site-to-site dedicati (classici link VPN utilizzati per creare una intranet con topologia a stella).

Problema

Creare un sistema di log centralizzato per tutti i dispositivi di rete, compresi i router degli uffici periferici.

Soluzione

Utilizzare una Linux box (CentOS 6) con a bordo il demone che funge da syslog server, ovvero rsyslog.

syslog

Configurazione della Linux box e del syslog server

Per prima cosa occorre fare in modo che la nostra Linux box sia in grado di ricevere correttamente (sulla porta UDP 514) i log inoltrati dai dispositivi di rete. Per fare ciò è sufficiente creare la seguente regola di netfilter (ultilizzando iptables):

-A INPUT -m state --state NEW -m udp -p udp -s 192.168.0.0/16 --dport 514 -j ACCEPT

ed aggiungerla all’interno del file /etc/sysconfig/iptables, per poi lanciare un:

[root@linuxbox ~]# service iptables restart

in modo da rendere la suddetta regola operativa (da notare che 192.168.0.0/16 è la subnet classe B che raggruppa tutte le /24 utilizzate dai branch office).

Una volta fatto ciò è necessario aggiungere la seguente direttiva all’interno del file di configurazione rsyslog, ovvero /etc/rsyslog.conf:

$template CiscoVPN,"/var/log/cisco/system-%HOSTNAME%.log"

*.* -?CiscoVPN

e creare la dir di target in cui verranno salvati i log, ovvero /var/log/cisco:

[root@linuxbox ~]# mkdir -p /var/log/cisco

A questo punto possiamo riavviare rsyslog in modo da rendere effettive le suddette modifiche:

[root@linuxbox ~]# service rsyslog restart

Configurazione dei dispositivi di rete

Per semplicità mi soffermerò solo ed esclusivamente nella configurazione dei router (Cisco) dei branch office. Tale operazione consiste in 2 fasi: la definizione di una sorgente SNTP affidabile ed identica per tutti i network device (in modo da poter effettuare un’eventuale correlazione tra gli eventi) e la configurazione del syslog server target.

Per configurare la sorgente SNTP è sufficiente lanciare il comando:

Router(config)# sntp server <IP del server SNTP>

Ad esempio, se volessimo utilizzare come server SNTP ntp1.inrim.it, dovremmo digitare:

Router(config)# sntp server 193.204.114.232

Per quanto riguarda la configurazione del target dei log, è sufficiente lanciare i seguenti comandi:

Router(config)# service timestamps log
Router(config)# logging source-interface Vlan1
Router(config)# logging <IP del syslog server>

Il primo comando serve a fare in modo che il timestamp dell’evento venga aggiunto automaticamente alla entry del log; il secondo comando specifica l’interfaccia dalla quale i log devono essere inviati (essendo in VPN, l’interfaccia di riferimento è quella della LAN, in questo caso la Vlan 1);  l’ultimo comando specifica molto banalmente l’indirizzo IP del syslog server.

Infine, controlliamo che i log vengano popolati in real time, lanciando il comando:

[root@linuxbox ~] #tail -f /var/log/system-<hostname>.log

dove <hostname> è l’hostname del dispositivo di rete di cui volete consultare il file di log.

Se tutto funziona a dovere possiamo dire di aver finalmente realizzato il nostro sistema di log centralizzato.

A presto.

CentOS 6 e contromisure agli attacchi DDoS: regole di firewalling basate sui netblock dei provider italiani

Scenario

Server Web Linux (basato su Apache) con CentOS 6 a bordo, dotato di 16 GB di RAM e 2 CPU con 4 core ciascuna. Totale assenza di firewall di frontend, ergo il filtraggio del traffico viene demandato direttamente al server in questione.

Problema

Da N giorni la suddetta macchina è vittima di attacchi di tipo DDoS, provenienti per lo più da IP stranieri (macchine zombie facenti parte di una botnet).

Soluzione

Creare delle regole netfilter ad hoc (mediante iptables), consentendo solo ed esclusivamente i netblock degli ISP italiani. Inoltre, per evitare che l’attaccante possa avvalersi di qualche proxy “aperto” made in Italy, sono stati bloccati ulteriori IP pubblici recuperati da un sito specifico. Infine, sono stati consentiti gli IP pubblici degli spider (aka crawler) utilizzati dai più importanti motori di ricerca (Google, Bing, Yahoo!), in modo tale da impedire che il sito Web hostato sul server venga penalizzato in termini di ranking.

Step 1: consentire gli IP italiani

Lo scrip bash (permit_ita.sh) che esegue tale operazione è il seguente:

#!/bin/bash

iptables -A INPUT -p tcp --dport 80 -j DROP
iptables -A INPUT -p tcp --dport 443 -j DROP

wget http://www.ipdeny.com/ipblocks/data/countries/it.zone -O ip_italiani.txt

while read line
do
    iptables -I INPUT -s $line -p tcp --dport 80 -j ACCEPT
    iptables -I INPUT -s $line -p tcp --dport 443 -j ACCEPT
done < ip_italiani.txt

iptables-save

Il suo funzionamento è banale: per prima cosa vengono create 2 regole netfilter per droppare tutto il traffico HTTP/HTTPS diretto al sito Web. Successivamente viene scaricato (mediante wget) il contenuto del sito http://www.ip-deny.com/ipblocks/data/countries/it.zone, in cui è presente l’elenco dei netblock italiani. Infine, vegnono consentiti i netblock in questione.

Step 2: bloccare i proxy made in Italy

A questo punto possiamo procedere con il blocco dei proxy “open” italiani. Per fare ciò possiamo utilizzare il seguente scrip bash (block_proxy.sh):

#!/bin/bash

wget --user-agent="Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3) Gecko/2008092416 Firefox/3.0.3"  http://spys.ru/free-proxy-list/IT/ -O lista_proxy.txt

grep -E -o "([0-9]{1,3}[\.]){3}[0-9]{1,3}" lista_proxy.txt | uniq > ip_proxy.txt

while read line
do
    iptables -I INPUT -s $line -p tcp --dport 80 -j DROP
    iptables -I INPUT -s $line -p tcp --dport 443 -j DROP
done < ip_proxy.txt

iptables-save

Il sito target (ovvero quello che contiene la lista dei proxy da bloccare) è http://spys.ru/free-proxy-list/IT/, il quale effettua un filtraggio dei client che possono accedervi utilizzando lo User Agent come discriminante (quindi non è possibile scaricarne il contenuto se non si effettua uno spoofing di tale parametro tramite wget e l’opzione –user-agent).

Inoltre, poichè il contenuto del sito non è una “lista piatta” di IP pubblici, è stato necessario filtrare il tutto utilizzando un’espressione regolare in grado di individuare i 4 ottetti tipici dell’IPv4.

Step 3: consentire gli spider dei motori di ricerca

Come ultima fase, occorre consentire gli IP degli spider, utilizzando tale scrip (permit_spider.sh):

#!/bin/bash

while read line
do
    iptables -I INPUT -s $line -p tcp --dport 80 -j ACCEPT -m comment --comment "crawler"
done < ip_spider.txt

iptables-save

Il contenuto del file ip_spider.txt potete ricavarlo da qui (Google), qui (Yahoo!) e qui (Bing ed altri).

A configurazione completata, possiamo saggiare il carico sul server (intento a droppare il traffico proveniente dalla botnet) utilizzando htop.

Se la macchina regge e le risorse hardware locali non sono allo stremo potremo finalmente dire di aver vinto.

Alla prossima.

Demone nodejs per CentOS 6

Come già affermato in questo post, nodejs ha rappresentato una vera e propria rivoluzione nella programmazione Web, in quanto ha consentito ad un linguaggio nativamente client-side come javascrip, di essere riadattato ed utilizzato come linguaggio server-side.

nodejs

Il funzionamento del suddetto applicativo è abbastanza banale: si richiama il binario da CLI e gli si da in pasto il file di configurazione del “server javascrip”, ad esempio:

[root@linuxbox ~]# node server.js

Per lasciarlo attivo in background occorre utilizzare un tool apposito come screen oppure un semplice nohup:

[root@linuxbox ~]# nohup node server.js

Va da se che tale soluzione per “demonizzare” nodejs non è proprio pulitissima ed è per questa ragione che ho deciso di creare un demone ad hoc per il suddetto applicativo:

 #!/bin/bash

# chkconfig: 2345 95 20
# description: nodejs service
# processname: nodejs

. /etc/rc.d/init.d/functions

USER="node"

DAEMON="/usr/bin/node"
ROOT_DIR="/home/nodejs"

SERVER="$ROOT_DIR/server.js"

for i in {1..8}

do

        do_start()
        {
                PORT="900$i"
                LOG_FILE="$ROOT_DIR/server$i.js.log"

                result=`ps aux | grep "server.js $PORT" | grep -v grep`
                if [ -z "$result" ] ; then
                echo -n $"Starting $SERVER $i: "
                runuser -l "$USER" -c "$DAEMON $SERVER $PORT >> $LOG_FILE &" && echo_success || echo_failure
                RETVAL=$?
                echo
                [ $RETVAL -eq 0 ]
                else
                echo "$SERVER $i already started."
                RETVAL=1
                fi
        }

        do_status()
        {
                PORT="900$i"

                result=`ps aux | grep "server.js $PORT" | grep -v grep`
                if [ -n "$result" ] ; then
                echo "$SERVER $i is started."
                RETVAL=0
                else
                echo "$SERVER $i is stopped."
                RETVAL=1
                fi
        }

done

do_stop()
{
        echo -n $"Stopping $SERVER:"
        killall -w node
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ]
}

case "$1" in
start)
        for i in {1..8}
        do
            do_start
        done
        ;;
stop)
        do_stop
        ;;
status)
        for i in {1..8}
        do
            do_status
        done
        ;;
restart)
        do_stop
        for i in {1..8}
        do
            do_start
        done
        ;;
*)

echo "Usage: $0 {start|stop|status|restart}"
        RETVAL=1
esac

exit $RETVAL

Tale demone, ad ogni avvio, esegue 8 istanze di nodejs, ciascuna delle quali è in ascolto su una porta dedicata (dalla 9001 alla 9008). Per non definire 8 funzioni do_start() e do_status() ho utilizzato un banale ciclo for e poichè la funzione do_stop() effettua un kill di tutti i processi il cui nome contiente la stringa “node” (killall -w), essa è stata estromessa dal predetto loop.

Inoltre, per ragioni di sicurezza, è stato definito un utente dedicato per l’esecuzione dell’applicativo (USER=”node”), la cui root directory è la propria home (ROOT_DIR=”/home/nodejs/), mentre il file di configurazione di nodejs è specificato all’interno della variabile SERVER (SERVER=”$ROOT_DIR/server.js”).

Infine, all’interno della funzione do_start(), ho definito il file di log per ciascuna istanza di nodejs, utilizzando la direttiva LOG_FILE=”$ROOT_DIR/server$i.js.log”.

Per completezza, di seguito riporto anche la versione senza cicli for:

#!/bin/bash

# chkconfig: 2345 95 20
# description: nodejs service
# processname: nodejs

. /etc/rc.d/init.d/functions

USER="node"

DAEMON="/usr/bin/node"
ROOT_DIR="/home/nodejs/"

SERVER="$ROOT_DIR/server.js"

PORT1="9001"
PORT2="9002"
PORT3="9003"
PORT4="9004"
PORT5="9005"
PORT6="9006"
PORT7="9007"
PORT8="9008"

LOG_FILE1="$ROOT_DIR/server1.js.log"
LOG_FILE2="$ROOT_DIR/server2.js.log"
LOG_FILE3="$ROOT_DIR/server3.js.log"
LOG_FILE4="$ROOT_DIR/server4.js.log"
LOG_FILE5="$ROOT_DIR/server5.js.log"
LOG_FILE6="$ROOT_DIR/server6.js.log"
LOG_FILE7="$ROOT_DIR/server7.js.log"
LOG_FILE8="$ROOT_DIR/server8.js.log"

do_start1()
{
        result1=`ps aux | grep "server.js $PORT1" | grep -v grep`
        if [ -z "$result1" ] ; then
        echo -n $"Starting $SERVER 1: "
        runuser -l "$USER" -c "$DAEMON $SERVER $PORT1 >> $LOG_FILE1 &" && echo_success || echo_failure
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ]
        else
        echo "$SERVER 1 already started."
        RETVAL=1
        fi
}

do_start2()
{
        result2=`ps aux | grep "server.js $PORT2" | grep -v grep`
        if [ -z "$result2" ] ; then
        echo -n $"Starting $SERVER 2: "
        runuser -l "$USER" -c "$DAEMON $SERVER $PORT2 >> $LOG_FILE2 &" && echo_success || echo_failure
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ]
        else
        echo "$SERVER 2 already started."
        RETVAL=1
        fi
}

do_start3()
{
        result3=`ps aux | grep "server.js $PORT3" | grep -v grep`
        if [ -z "$result3" ] ; then
        echo -n $"Starting $SERVER 3: "
        runuser -l "$USER" -c "$DAEMON $SERVER $PORT3 >> $LOG_FILE3 &" && echo_success || echo_failure
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ]
        else
        echo "$SERVER 3 already started."
        RETVAL=1
        fi
}

do_start4()
{
        result4=`ps aux | grep "server.js $PORT4" | grep -v grep`
        if [ -z "$result4" ] ; then
        echo -n $"Starting $SERVER 4: "
        runuser -l "$USER" -c "$DAEMON $SERVER $PORT4 >> $LOG_FILE4 &" && echo_success || echo_failure
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ]
        else
        echo "$SERVER 4 already started."
        RETVAL=1
        fi
}

do_start5()
{
        result5=`ps aux | grep "server.js $PORT5" | grep -v grep`
        if [ -z "$result5" ] ; then
        echo -n $"Starting $SERVER 5: "
        runuser -l "$USER" -c "$DAEMON $SERVER $PORT5 >> $LOG_FILE5 &" && echo_success || echo_failure
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ]
        else
        echo "$SERVER 5 already started."
        RETVAL=1
        fi
}

do_start6()
{
        result6=`ps aux | grep "server.js $PORT6" | grep -v grep`
        if [ -z "$result6" ] ; then
        echo -n $"Starting $SERVER 6: "
        runuser -l "$USER" -c "$DAEMON $SERVER $PORT6 >> $LOG_FILE6 &" && echo_success || echo_failure
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ]
        else
        echo "$SERVER 6 already started."
        RETVAL=1
        fi
}

do_start7()
{
        result7=`ps aux | grep "server.js $PORT7" | grep -v grep`
        if [ -z "$result7" ] ; then
        echo -n $"Starting $SERVER 7: "
        runuser -l "$USER" -c "$DAEMON $SERVER $PORT7 >> $LOG_FILE7 &" && echo_success || echo_failure
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ]
        else
        echo "$SERVER 7 already started."
        RETVAL=1
        fi
}

do_start8()
{
        result8=`ps aux | grep "server.js $PORT8" | grep -v grep`
        if [ -z "$result8" ] ; then
        echo -n $"Starting $SERVER 8: "
        runuser -l "$USER" -c "$DAEMON $SERVER $PORT8 >> $LOG_FILE8 &" && echo_success || echo_failure
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ]
        else
        echo "$SERVER 8 already started."
        RETVAL=1
        fi
}

do_status1()
{
        result1=`ps aux | grep "server.js $PORT1" | grep -v grep`
        if [ -n "$result1" ] ; then
        echo "$SERVER 1 is started."
        RETVAL=0
        else
        echo "$SERVER 1 is stopped."
        RETVAL=1
        fi
}

do_status2()
{
        result2=`ps aux | grep "server.js $PORT2" | grep -v grep`
        if [ -n "$result2" ] ; then
        echo "$SERVER 2 is started."
        RETVAL=0
        else
        echo "$SERVER 2 is stopped."
        RETVAL=1
        fi
}

do_status3()
{
        result3=`ps aux | grep "server.js $PORT3" | grep -v grep`
        if [ -n "$result3" ] ; then
        echo "$SERVER 3 is started."
        RETVAL=0
        else
        echo "$SERVER 3 is stopped."
        RETVAL=1
        fi
}

do_status4()
{
        result4=`ps aux | grep "server.js $PORT4" | grep -v grep`
        if [ -n "$result4" ] ; then
        echo "$SERVER 4 is started."
        RETVAL=0
        else
        echo "$SERVER 4 is stopped."
        RETVAL=1
        fi
}

do_status5()
{
        result5=`ps aux | grep "server.js $PORT5" | grep -v grep`
        if [ -n "$result5" ] ; then
        echo "$SERVER 5 is started."
        RETVAL=0
        else
        echo "$SERVER 5 is stopped."
        RETVAL=1
        fi
}

do_status6()
{
        result6=`ps aux | grep "server.js $PORT6" | grep -v grep`
        if [ -n "$result6" ] ; then
        echo "$SERVER 6 is started."
        RETVAL=0
        else
        echo "$SERVER 6 is stopped."
        RETVAL=1
        fi
}

do_status7()
{
        result7=`ps aux | grep "server.js $PORT7" | grep -v grep`
        if [ -n "$result7" ] ; then
        echo "$SERVER 7 is started."
        RETVAL=0
        else
        echo "$SERVER 7 is stopped."
        RETVAL=1
        fi
}

do_status8()
{
        result8=`ps aux | grep "server.js $PORT8" | grep -v grep`
        if [ -n "$result8" ] ; then
        echo "$SERVER 8 is started."
        RETVAL=0
        else
        echo "$SERVER 8 is stopped."
        RETVAL=1
        fi
}

do_stop()
{
        echo -n $"Stopping $SERVER:"
        killall -w node
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ]
}

case "$1" in
start)
        do_start1
        do_start2
        do_start3
        do_start4
        do_start5
        do_start6
        do_start7
        do_start8
        ;;
stop)
        do_stop
        ;;
status)
        do_status1
        do_status2
        do_status3
        do_status4
        do_status5
        do_status6
        do_status7
        do_status8
        ;;
restart)
        do_stop
        do_start1
        do_start2
        do_start3
        do_start4
        do_start5
        do_start6
        do_start7
        do_start8
        ;;
*)

echo "Usage: $0 {start|stop|status|restart}"
        RETVAL=1
esac

exit $RETVAL

Basta dare una semplice occhiata e vi renderete subito conto del perchè abbia preferito la prima versione a quest’ultima.

Non ci rimane che rendere il demone eseguibile:

[root@linuxbox ~]# chmod +x nodejs

spostarlo nella directory /etc/init.d:

[root@linuxbox ~]# mv nodejs /etc/init.d

ed avviarlo:

[root@linuxbox ~]# service nodejs start

E’ tutto.

checksecurity.sh: script bash per monitorare gli aggiornamenti critici su CentOS 6

Poichè devo gestire un elevato numero di VM *nix, mi è indispensabile riuscire ad automatizzare quanti più task possibili, tenendo sempre a mente tale regola:

                                                                        a good sysadmin is a lazy one

Uno di questi task riguarda le notifiche per gli aggiornamenti critici di sistema, soprattutto per ciò che concerne l’aspetto della cyber security.

A tal proposito, ho realizzato uno scrip bash in grado di verificare la presenza di eventuali aggiornamenti e di inviarmi successiva notifica via email.  Starà a me, in un secondo momento, decidere quando e se installare gli aggiornamenti proposti.

I tool necessari al suo funzionamento sono 2, ovvero yum-security e mutt. Procediamo dunque con la loro installazione mediante yum:

[root@linuxbox ~]# yum install yum-plugin-security mutt -y

bashEd ecco lo scrip:

#!/bin/bash

logfile=/var/log/checksecurity.log

data=`date +%d-%m-%Y`

destinatario=vostro.indirizzo@email.it

echo "$data: Checking for security updates..." >> $logfile

yum clean all

yum list-security >> /root/checksec/tmp

security=`cat /root/chcksec/tmp | grep security | grep -v Loaded`

bugfix=`cat /root/checksec/tmp | grep bugfix`

cve=`cat /root/checksec/tmp | grep cve`

if [ -n "$security" ];then
echo "$data: security updates available" > /root/checksec/out
fi

if [ -n "$bugfix" ];then
echo "$data: bugfix updates available" >> /root/checksec/out
fi

if [ -n "$cve" ];then
echo "$data: cve updates available" >> /root/checksec/out
fi

if [ -s /root/checksec/out ];then

cat /root/checksec/tmp >> /root/checksec/out

cat /root/checksec/out >> $logfile

cat /root/checksec/out | mutt -s "GESTORE01: security, bugfix and cve system report" $destinatario

rm /root/checksec/out

else

echo "$data: Nothing to do, exiting..." | tee -a $logfile

fi

rm /root/checksec/tmp

exit 0;

Ci rimane solo rendere lo scrip eseguibile (chmod +x /root/checksec/checksecurity.sh) ed aggiungerlo a crontab.

Alla prossima.

Auguri!

Ecco una strofa di “Jingle Bells”, rivista in chiave linuxiana:

  Jingle bells, CentOS swells, when you add new stuff,
  Program here, Program there, never is enough, hey!
  gzip file, bz2, Fun for me and you!
  Time flies by in a bash shell if you've nothing else to do!

Quale modo migliore per augurarvi un felice Natale? 😉

Installare e configurare NFS

L’acronimo NFS sta per Network File System ed è un sistema di sharing utilizzato in ambiente Linux. A differenza di Samba, che consente ad un sistema *nix di fungere da file server per macchine Windows, NFS è riservato solo ed esclusivamente ai sistemi operativi Unix-like.

linux, windows, samba, nfs, sharing, file server, rpc, portmap, ACL, fstab, mount

Configurarlo e farlo funzionare non è banale, in quanto, oltre alla configurazione del server, occorre lavorare anche sui client, facendo in modo che possano accedere alle directory condivise.

Configurazione del server

Per fare in modo che una macchina Linux possa funzionare da server NFS è necessario installare i seguenti pacchetti:

[root@server ~]# yum install nfs-server
[root@server ~]# yum install portmap

Il primo, ovviamente, è il demone che tira su il servizio NFS vero e proprio; il secondo, invece, serve a gestire le chiamate RPC.

Una volta installati i suddetti pacchetti, passiamo alla configurazione di NFS. Per fare ciò occorre editare il file /etc/exports:

[root@server etc]#nano exports

aggiungendo la directory da condividere (con pathname assoluto) e relativa ACL. Quest’ultima permetterà di fare una distinzione tra le macchine che possono avere accesso alle risorse condivise e quelle a cui l’accesso è stato negato.

/var/www/html/share                192.168.49.0/255.255.255.24 (rw,sync)

Le ultime due flag indicano che le macchine a cui è consentito l’accesso possono operare sia in lettura che in scrittura (rw) e che il contenuto della directory deve essere costantemente sincronizzato tra client e server (sync). Ovviamente, la directory da sharare deve essere esistente, dunque, se ancora non l’avete creata, fatelo mediante un banale mkdir <nomedirectory>.

Inoltre, poichè il meccanismo di controllo degli accessi definito in precedenza è abbastanza blando (si basa sulo ed esclusivamente sull’indirizzo IP delle macchine che vogliono accedere agli share), è opportuno fare in modo che tali servizi non vengano esposti all’esterno, facendo uso di un firewall o di un dispositivo che implementa il NAT/PAT.

Bene, non ci resta che avviare i servizi nfs e portmap:

[root@server etc]# service portmap start
[root@server etc]# service nfs start

Se tutto è andato a buon fine, lanciando un netstat -anp, dovrebbero risultare in ascolto le seguenti porte:

111 UDP (portmap)

2049 TCP/UDP (NFS)

Abilitiamo l’avvio automatico dei suddetti servizi:

[root@server etc]# chkconfig --levels 2345 nfs on
[root@server etc]# chkconfig --levels 2345 portmap on

e lato server abbiamo finito.

Configurazione dei client

Come primo step, è necessario installare il seguente pacchetto:

[root@client ~]# yum install nfs-utils

Successivamente, la cosa più semplice da fare per consentire ai client di accedere alle directory condivise, consiste nell’editare il file /etc/fstab:

[root@client ~]# nano /etc/fstab

aggiungendo una entry del tipo:

<IP LAN server>:/var/www/html/share    /var/www/html/share    nfs    hard,intr,rw,sync 0 0

In particolare, in questa direttiva sono presenti i seguenti campi:

1) share remota;

2) punto di mount locale (che deve essere una directory esistente);

3) tipo di file system;

4) ulteriori flag.

Per montare la share appena creata possiamo lanciare il seguente comando:

[root@linux ~]# mount -a

che monta tutte le partizioni definite nel file fstab, compresa quella NFS.

Per verificare che la share sia effettivamente up, basta digitare il comando mount (che per default mostra tutte le partizioni già montate).

Infine, se si aggiunge una nuova share e la si vuole rendere subito disponibile (senza un restart del demone NFS), è sufficiente lanciare sul server il seguente comando:

[root@server etc]# exportfs -a

Alla prossima.

 

Linux alias

Creare degli alias mediante shell Linux è un’operazione banale e di un’utilità pazzesca. Infatti, essi consentono di ridurre notevolmente il numero di flag da digitare, semplicemente associando il comando originario ad uno molto più semplice da ricordare.

tux1.jpg

Per quanto mi riguarda, dato che spesso e volentieri mi ritrovo dietro proxy e sono costretto ad utilizzare un mio server italiano come bouncer per accedere alle macchine sparse qua e là per il globo, lanciare a mano delle sessioni SSH specificando ogni volta username, porta di destinazione, ecc. risulta essere un’operazione tediosa ed un’insopportabile perdita di tempo. Sono corso, quindi, ai ripari, semplicemente digitando un comando simile al seguente:

nightfly@nightbox:~$ alias ssh_server1='ssh -p <porta su cui è in ascolto il demone SSH> -l <nomeutente> <indirizzo IP del server>'

Per listare tutti gli alias attivi occorre digitare il comando alias:

nightfly@nightbox:~$ alias

il cui output sarà simile al seguente:

alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l='ls -CF'
alias la='ls -A'
alias ll='ls -alF'
alias ls='ls --color=auto'

Mentre, per rimuovere un alias, basta scrivere:

unalias <nomealias>

Attenzione però, gli alias così definiti valgono solo per la sessione in cui vengono creati. Per fare in modo che siano permanenti è necessario inserirli all’interno del file /home/nomeutente/.bashrc.

Alla prossima.