Ubuntu: analisi e debug di un’interfaccia di rete malfunzionante

Di recente, analizzando i log di uno dei server che gestisco, mi sono accorto che una delle sue interfacce di rete continuava a generare tutta una serie di eventi del tipo:

root@linux-box:~$ dmesg | grep eth0
[  184.348573] 8139too 00:40:f4:44:68:8e: eth0: link up
[  190.271409] 8139too 00:40:f4:44:68:8e: eth0: link up
[  196.374125] 8139too 00:40:f4:44:68:8e: eth0: link up
[  201.823936] 8139too 00:40:f4:44:68:8e: eth0: link up
[  208.089862] 8139too 00:40:f4:44:68:8e: eth0: link up
[  212.200536] 8139too 00:40:f4:44:68:8e: eth0: link up
[  216.950829] 8139too 00:40:f4:44:68:8e: eth0: link up
[  221.071493] 8139too 00:40:f4:44:68:8e: eth0: link up
[  226.731134] 8139too 00:40:f4:44:68:8e: eth0: link up
[  230.778527] 8139too 00:40:f4:44:68:8e: eth0: link up
[  234.126353] 8139too 00:40:f4:44:68:8e: eth0: link up
[  238.936576] 8139too 00:40:f4:44:68:8e: eth0: link up
[  244.859427] 8139too 00:40:f4:44:68:8e: eth0: link up
[  250.845563] 8139too 00:40:f4:44:68:8e: eth0: link up
[  256.831661] 8139too 00:40:f4:44:68:8e: eth0: link up
[  262.458027] 8139too 00:40:f4:44:68:8e: eth0: link up
[  266.428794] 8139too 00:40:f4:44:68:8e: eth0: link up
[  271.305659] 8139too 00:40:f4:44:68:8e: eth0: link up
[  277.091885] 8139too 00:40:f4:44:68:8e: eth0: link up
[  282.768241] 8139too 00:40:f4:44:68:8e: eth0: link up
[  287.102103] 8139too 00:40:f4:44:68:8e: eth0: link up
[  290.866316] 8139too 00:40:f4:44:68:8e: eth0: link up
[  294.267496] 8139too 00:40:f4:44:68:8e: eth0: link up

ubuntu

In più, essa risultava completamente “sorda”, nel senso che anche sniffando il traffico mediante tcpdump, non vi era evidenza di frame/pacchetti di alcun genere, nonostante fosse collegata ad un segmento di rete piuttosto popolato.

Alla luce di ciò, le cause del suddetto malfunzionamento sarebbero potute essere 2:

1) guasto hardware;
2) aggiornamento che ha compromesso i driver del kernel che si interfacciano con la scheda (leggasi moduli), rendendola inutilizzabile.

Prima di procedere con l’analisi, però, è opportuno capire come avviene il riconoscimento dell’interfaccia di rete da parte del sistema operativo durante la fase di boot.

Chipset e moduli del kernel

Durante l’accesione (boot) della macchina, il sistema operativo riconosce la scheda di rete “dialongando” con il chipset di cui è dotata. Per individuarlo è sufficiente lanciare il seguente comando (con relativo output):

root@linux-box:~# lspci | grep Ethernet

04:01.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL-8139/8139C/8139C+ (rev 10)

Nella fattispecie, il chipset utilizzato dalla scheda è Realtek.

Il modulo del kernel in grado di interfacciarsi con essa prende il nome di r8139too e deve essere caricato in fase di avvio. Per verificare che il suddetto modulo sia effettivamente up è sufficiente lanciare il comando:

root@linux-box:~$ lsmod | grep 8139

il cui output sarà simile al seguente:

8139too                32177  0
8139cp                 27360  0

Udev e nomenclatura

Se il modulo è stato correttamente caricato, la scheda di rete può essere effettivamente “riconosciuta” come tale ed il sistema operativo sarà in grado di assegnarle un nome.

Durante tale fase entra in gioco il demone udev, che “leggerà” il contenuto del file di configurazione dedicato alle interfacce di rete, ovvero /etc/udev/rules.d/70-persistent-net.rules:

root@linux-box:~$ cat /etc/udev/rules.d/70-persistent-net.rules

# PCI device 0x10ec:/sys/devices/pci0000:00/0000:00:1e.0/0000:04:01.0 (8139too)
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:40:f4:44:68:8e", ATTR{dev_id}=="0x0", ATTR{type}=="1", NAME="eth0"

La suddetta regola di esempio parla chiaro: appena viene identificata una scheda di rete recante come indirizzo MAC 00:40:f4:44:68:8e, come id 0x0 e come tipo 1, le dovrà essere assegnato come nome eth0.

Configurazione

A questo punto la scheda è pronta per essere configurata, secondo quanto definito all’interno del file /etc/network/interfaces:

auto eth0
iface eth0 inet static
address 192.168.11.1
netmask 255.255.255.0

Comandi di diagnostica

Se tutto è filato per il verso giusto, lanciando un semplice ifconfig, la suddetta scheda di rete sarà tra quelle disponibili:

root@linux-box:~$ ifconfig eth0
eth0      Link encap:Ethernet  IndirizzoHW 00:40:f4:44:68:8e
          indirizzo inet:192.168.1.1  Bcast:192.168.11.255  Maschera:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1989751 errors:0 dropped:0 overruns:0 frame:0
          TX packets:3500430 errors:0 dropped:0 overruns:0 carrier:0
          collisioni:0 txqueuelen:1000
          Byte RX:339007498 (339.0 MB)  Byte TX:3756299292 (3.7 GB)
          Interrupt:16 Indirizzo base:0xe800

Inoltre, è possibile visualizzare il modulo in uso per interfacciarsi con la suddetta scheda, avvalendosi di ethtool con l’opzione -k:

root@linux-box:~$ ethtool -i eth0

il cui output sarà simile al seguente:

driver: 8139too
version: 0.9.28
firmware-version:
bus-info: 0000:04:01.0
supports-statistics: yes
supports-test: no
supports-eeprom-access: no
supports-register-dump: no

Per identificare, invece, alcuni dei suoi parametri di funzionamento, quali autonegoziazione, velocità, duplex, ecc., è sufficiente lanciare il comando:

root@linux-box:~# ethtool eth0

che ci darà un risultato simile al seguente:

Settings for eth0:
        Supported ports: [ TP MII ]
        Supported link modes:   10baseT/Half 10baseT/Full
                                100baseT/Half 100baseT/Full
        Supported pause frame use: No
        Supports auto-negotiation: Yes
        Advertised link modes:  10baseT/Half 10baseT/Full
                                100baseT/Half 100baseT/Full
        Advertised pause frame use: No
        Advertised auto-negotiation: Yes
        Link partner advertised link modes:  10baseT/Half 10baseT/Full
                                             100baseT/Half 100baseT/Full
        Link partner advertised pause frame use: Symmetric
        Link partner advertised auto-negotiation: Yes
        Speed: 100Mb/s
        Duplex: Full
        Port: MII
        PHYAD: 32
        Transceiver: internal
        Auto-negotiation: on
        Supports Wake-on: pumbg
        Wake-on: g
        Current message level: 0x00000007 (7)
                               drv probe link
        Link detected: yes

In alternativa, si possono ottenere delle informazioni più sintetiche utilizzando il più datato (e meno completo) mii-tool:

root@linux-box:~$ mii-tool eth0
eth0: negotiated 100baseTx-FD, link ok

Identificazione della causa

A valle delle riflessioni fatte fin’ora, tutto ciò che riguarda la scheda risulta coerente e conforme con quanto ci si aspettava, per cui è stato facile intuire, andando per esclusione, che si trattava, banalmente, di un guasto hardware.

Una volta sostituita la scheda, infatti, tutto ha ripreso a funzionare correttamente.

Alla prossima.

CentOS 6: debug del proxy Squid mediante cURL

Di recente, durante uno dei miei controlli di routine presso la rete di un cliente, mi sono accorto che il proxy ivi utilizzato (Squid) mandava in timeout tutte le richieste HTTP/HTTPS dirette al sito paypal.com.

squidOra, premesso che esistono diversi modi per fare un po’ di debug sul proxy, utilizzando ad esempio dei tool sviluppati ad hoc (uno su tutti squidclient), ho preferito adoperare semplicemente cURL, fondamentalmente per 3 motivi:

1) la sua semplicità di impiego;
2) l’ottima documentazione a corredo;
3) la possibilità di visualizzare gli header HTTP di ciascuna richiesta (tracciando eventuali redirect).

Ma bando alle ciance ed ecco come ho individuato (e risolto) l’anomalia riscontrata.

Test di funzionamento

Per prima cosa ho effettuato 2 differenti richieste: la prima diretta ad http://www.paypal.com e la seconda verso http://paypal.com, avvalendomi, rispettivamente, delle flag -v (verbose), -k (per ignorare eventuali problemi di certificati SSL/TLS), -x (per definire il proxy da utilizzare) e – L (che mi permette di indicare il sito target della richiesta). Per http://www.paypal.com ho ottenuto:

root@linux-box:~# curl -v -k -x http://192.168.10.1:3128 -L http://www.paypal.com
* About to connect() to proxy 192.168.10.1 port 3128 (#0)
*   Trying 192.168.10.1... connected
> GET http://www.paypal.com HTTP/1.1
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: www.paypal.com
> Accept: */*
> Proxy-Connection: Keep-Alive
>
* HTTP 1.0, assume close after body
< HTTP/1.0 302 Moved Temporarily
< Date: Tue, 21 Feb 2017 08:16:33 GMT
< Server: Apache
< Location: https://192.168.10.1/block.html
< Vary: Accept-Encoding
< Content-Length: 214
< Content-Type: text/html; charset=iso-8859-1
< X-Cache: MISS from localhost
< X-Cache-Lookup: MISS from localhost:3128
< Via: 1.0 localhost (squid/3.1.19)
* HTTP/1.0 connection set to keep alive!
< Connection: keep-alive
<
* Ignoring the response-body
* Connection #0 to host 192.168.10.1 left intact
* Issue another request to this URL: 'https://192.168.10.1/block.html'
* About to connect() to proxy 192.168.10.1 port 3128 (#1)
*   Trying 192.168.10.1... connected
* Establish HTTP proxy tunnel to 192.168.10.1:443
> CONNECT 192.168.10.1:443 HTTP/1.1
> Host: 192.168.10.1:443
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Proxy-Connection: Keep-Alive
>
< HTTP/1.0 200 Connection established
<
* Proxy replied OK to CONNECT request
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /*/*/certs
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Server key exchange (12):
* SSLv3, TLS handshake, Server finished (14):
* SSLv3, TLS handshake, Client key exchange (16):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSL connection using ECDHE-RSA-AES256-GCM-SHA384
* Server certificate:
*        subject: C=IT; ST=Some-State; L=Roma; O=Test; CN=Test; emailAddress=hidden@email.it
*        start date: 2013-02-25 15:48:44 GMT
*        expire date: 2014-02-25 15:48:44 GMT
*        issuer: C=IT; ST=Some-State; L=Roma; O=Test; CN=Test; emailAddress=hidden@email.it
*        SSL certificate verify result: self signed certificate (18), continuing anyway.
> GET /block.html HTTP/1.0
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: 192.168.10.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Tue, 21 Feb 2017 08:16:33 GMT
< Server: Apache
< Last-Modified: Mon, 25 Feb 2013 16:13:19 GMT
< ETag: "f293-289-4d68ed1c4eeb4"
< Accept-Ranges: bytes
< Content-Length: 649
< Vary: Accept-Encoding
< Connection: close
< Content-Type: text/html
<
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Proibito</title>
</head>
<body>
<p align="center"><img src="http://192.168.10.1/images/forbidden.png" alt="forbidden" vspace="100"/></p>
<p align="center"><strong>I contenuti del sito sono stati bloccati per ragioni di sicurezza. Per maggiori informazioni contattare l'amministratore</strong></p>
</body>
</html>
* Closing connection #1
* SSLv3, TLS alert, Client hello (1):
* Closing connection #0

mentre per http://paypal.com l’output è stato il seguente:

root@linux-box:~# curl -v -k -x http://192.168.10.1:3128 -L http://paypal.com
* About to connect() to proxy 192.168.10.1 port 3128 (#0)
*   Trying 192.168.10.1... connected
> GET http://paypal.com HTTP/1.1
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: paypal.com
> Accept: */*
> Proxy-Connection: Keep-Alive
>
* HTTP 1.0, assume close after body
< HTTP/1.0 302 Moved Temporarily
< Date: Tue, 21 Feb 2017 08:17:36 GMT
< Server: Apache
< Location: https://192.168.10.1/block.html
< Vary: Accept-Encoding
< Content-Length: 214
< Content-Type: text/html; charset=iso-8859-1
< X-Cache: MISS from localhost
< X-Cache-Lookup: MISS from localhost:3128
< Via: 1.0 localhost (squid/3.1.19)
* HTTP/1.0 connection set to keep alive!
< Connection: keep-alive
<
* Ignoring the response-body
* Connection #0 to host 192.168.10.1 left intact
* Issue another request to this URL: 'https://192.168.10.1/block.html'
* About to connect() to proxy 192.168.10.1 port 3128 (#1)
*   Trying 192.168.10.1... connected
* Establish HTTP proxy tunnel to 192.168.10.1:443
> CONNECT 192.168.10.1:443 HTTP/1.1
> Host: 192.168.10.1:443
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Proxy-Connection: Keep-Alive
>
< HTTP/1.0 200 Connection established
<
* Proxy replied OK to CONNECT request
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /*/*/certs
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Server key exchange (12):
* SSLv3, TLS handshake, Server finished (14):
* SSLv3, TLS handshake, Client key exchange (16):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSL connection using ECDHE-RSA-AES256-GCM-SHA384
* Server certificate:
*        subject: C=IT; ST=Some-State; L=Roma; O=Test; CN=Test; emailAddress=hidden@email.it
*        start date: 2013-02-25 15:48:44 GMT
*        expire date: 2014-02-25 15:48:44 GMT
*        issuer: C=IT; ST=Some-State; L=Roma; O=Test; CN=Test; emailAddress=hidden@email.it
*        SSL certificate verify result: self signed certificate (18), continuing anyway.
> GET /block.html HTTP/1.0
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: 192.168.10.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Tue, 21 Feb 2017 08:17:36 GMT
< Server: Apache
< Last-Modified: Mon, 25 Feb 2013 16:13:19 GMT
< ETag: "f293-289-4d68ed1c4eeb4"
< Accept-Ranges: bytes
< Content-Length: 649
< Vary: Accept-Encoding
< Connection: close
< Content-Type: text/html
<
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Proibito</title>
</head>
<body>
<p align="center"><img src="http://192.168.10.1/images/forbidden.png" alt="forbidden" vspace="100"/></p>
<p align="center"><strong>I contenuti del sito sono stati bloccati per ragioni di sicurezza. Per maggiori informazioni contattare l'amministratore</strong></p>
</body>
</html>
* Closing connection #1
* SSLv3, TLS alert, Client hello (1):
* Closing connection #0

Individuazione della causa di malfuzionamento

In entrambi i casi il proxy mi ha reindirizzato alla pagina di notifica di squidGuard, ovvero il software che si occupa del filtraggio dei siti Web. Ciò ha fatto scattare un campanello di allarme nella mia testa, in quanto entrambi i domini dovrebbero essere già consentiti, ragion per cui ho deciso di indagare ulteriormente analizzando i log delle blacklist di squidGuard:

root@linux-box:/var/log/squid# tail -f spyware.log
2017-02-21 09:57:06 [1636] Request(default/spyware/-) http://www.paypal.com/ 192.168.10.1/proxy - GET REDIRECT

Una volta individuata la blacklist di interesse (ovvero spyware) ho focalizzato alla mia attenzione sul file domains, andando alla ricerca di tutte le stringhe contenenti paypal.com. Così facendo, una entry ha subito destato in me qualche sospetto, ovvero:

-paypal.com

che ho prontamente sostituito con:

\-paypal.com

aggiungendo semplicemente il carattere di escape (\) davanti al carattere .

Ho quindi ricompilato le blacklist, settando i dovuti permessi e ricaricando la configurazione di Squid proxy:

root@linux-box:~# squidGuard -d -C all 
root@linux-box:~# chown proxy:proxy -R /var/lib/squidguard/db
root@linux-box:~# squid3 -k reconfigure

A questo punto ho lanciato una nuova richiesta verso http://paypal.com, proprio per sincerarmi che la entry errata contenuta nel file domains fosse proprio quella modificata in precedenza:

root@linux-box:/var/lib/squidguard/db/spyware# curl -v -k -x http://192.168.10.1:3128 -L http://paypal.com/
* About to connect() to proxy 192.168.10.1 port 3128 (#0)
*   Trying 192.168.10.1... connected
> GET http://paypal.com/ HTTP/1.1
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: paypal.com
> Accept: */*
> Proxy-Connection: Keep-Alive
>
* HTTP 1.0, assume close after body
< HTTP/1.0 302 Moved Temporarily
< Date: Tue, 21 Feb 2017 10:06:48 GMT
< Location: https://paypal.com/
< Server: BigIP
< Content-Length: 0
< X-Cache: MISS from localhost
< X-Cache-Lookup: MISS from localhost:3128
< Via: 1.0 localhost (squid/3.1.19)
* HTTP/1.0 connection set to keep alive!
< Connection: keep-alive
<
* Connection #0 to host 192.168.10.1 left intact
* Issue another request to this URL: 'https://paypal.com/'
* About to connect() to proxy 192.168.10.1 port 3128 (#1)
*   Trying 192.168.10.1... connected
* Establish HTTP proxy tunnel to paypal.com:443
> CONNECT paypal.com:443 HTTP/1.1
> Host: paypal.com:443
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Proxy-Connection: Keep-Alive
>
< HTTP/1.0 200 Connection established
<
* Proxy replied OK to CONNECT request
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Server finished (14):
* SSLv3, TLS handshake, Client key exchange (16):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSL connection using AES256-GCM-SHA384
* Server certificate:
*        subject: C=US; ST=California; L=San Jose; O=PayPal, Inc.; OU=PayPal Production; CN=paypal.com
*        start date: 2016-11-04 00:00:00 GMT
*        expire date: 2018-11-01 12:00:00 GMT
*        issuer: C=US; O=DigiCert Inc; OU=www.digicert.com; CN=DigiCert SHA2 High Assurance Server CA
*        SSL certificate verify ok.
> GET / HTTP/1.0
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: paypal.com
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 301 Moved Permanently
< Location: https://www.paypal.com/
< Strict-Transport-Security: max-age=63072000
< Connection: close
< Content-Length: 0
<
* Closing connection #1
* SSLv3, TLS alert, Client hello (1):
* Issue another request to this URL: 'https://www.paypal.com/'
* About to connect() to proxy 192.168.10.1 port 3128 (#1)
*   Trying 192.168.10.1... connected
* Establish HTTP proxy tunnel to www.paypal.com:443
> CONNECT www.paypal.com:443 HTTP/1.1
> Host: www.paypal.com:443
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Proxy-Connection: Keep-Alive
>
< HTTP/1.0 200 Connection established
<
* Proxy replied OK to CONNECT request
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Server key exchange (12):
* SSLv3, TLS handshake, Server finished (14):
* SSLv3, TLS handshake, Client key exchange (16):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSL connection using ECDHE-RSA-AES128-GCM-SHA256
* Server certificate:
*        subject: 1.3.6.1.4.1.311.60.2.1.3=US; 1.3.6.1.4.1.311.60.2.1.2=Delaware; businessCategory=Private Organization; serialNumber=3014267; C=US; postalCode=95131-2021; ST=California; L=San Jose; street=2211 N 1st St; O=PayPal, Inc.; OU=CDN Support; CN=www.paypal.com
*        start date: 2016-02-02 00:00:00 GMT
*        expire date: 2017-10-30 23:59:59 GMT
*        issuer: C=US; O=Symantec Corporation; OU=Symantec Trust Network; CN=Symantec Class 3 EV SSL CA - G3
*        SSL certificate verify ok.
> GET / HTTP/1.0
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: www.paypal.com
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 302 Moved Temporarily
< Server: Apache
< X-Recruiting: If you are reading this, maybe you should be working at PayPal instead! Check out https://www.paypal.com/us/webapps/mpp/paypal-jobs
< Paypal-Debug-Id: c075f46342370
< Cache-Control: no-cache
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< X-FRAME-OPTIONS: SAMEORIGIN
< Content-Security-Policy: default-src 'self' https://*.paypal.com https://*.paypalobjects.com https://nexus.ensighten.com 'unsafe-inline'; frame-src 'self' https://*.brighttalk.com https://*.paypal.com https://*.paypalobjects.com https://www.youtube.com/embed/ https://www.paypal-donations.com https://www.paypal-donations.co.uk https://*.qa.missionfish.org https://www.youtube-nocookie.com https://www.xoom.com https://*.pub.247-inc.net/; script-src 'self' https://*.brighttalk.com https://*.paypal.com https://*.paypalobjects.com https://www.youtube.com/iframe_api https://s.ytimg.com/yts/jsbin/ https://*.t.eloqua.com https://img.en25.com/i/elqCfg.min.js https://nexus.ensighten.com/ 'unsafe-inline' 'unsafe-eval'; connect-src 'self' https://*.paypal.com https://*.paypalobjects.com https://*.salesforce.com https://*.force.com https://*.eloqua.com https://nexus.ensighten.com https://storelocator.api.where.com https://api.paypal-retaillocator.com https://nominatim.openstreetmap.org https://www.paypal-biz.com; img-src 'self' * data:; object-src 'self' https://*.paypal.com https://*.paypalobjects.com; font-src 'self' https://*.paypalobjects.com;
< HTTP_X_PP_AZ_LOCATOR: slcb.slc
< Paypal-Debug-Id: c075f46342370
< Location: /it/home
< Content-Encoding: gzip
< Cache-Control: max-age=0, no-cache, no-store, must-revalidate
< Pragma: no-cache
< Content-Type: text/plain; charset=utf-8
< DC: phx-origin-www-1.paypal.com
< Content-Length: 56
< X-EdgeConnect-MidMile-RTT: 3
< X-EdgeConnect-Origin-MEX-Latency: 198
< X-EdgeConnect-MidMile-RTT: 169
< X-EdgeConnect-Origin-MEX-Latency: 198
< Date: Tue, 21 Feb 2017 10:06:51 GMT
< Connection: close
< Set-Cookie: LANG=it_IT%3BIT; Domain=.paypal.com; Path=/; Expires=Tue, 21 Feb 2017 18:52:46 GMT; HttpOnly
< Set-Cookie: tsrce=mppnodeweb; Domain=.paypal.com; Path=/; Expires=Wed, 22 Feb 2017 10:06:50 GMT; HttpOnly; Secure
< Set-Cookie: x-pp-s=eyJ0IjoiMTQ4NzY3MTYxMTM5NCIsIm0iOiIwIn0; Domain=.paypal.com; Path=/; HttpOnly; Secure
< Set-Cookie: nsid=s%3AUhjv0IeCf2Lsd4mAbdfaZCowZwbnEoLG.VPNYMobMlVf8MPI4EqbaGJHWsctx9knCbLdeDqVeGhg; Path=/; HttpOnly; Secure
< Set-Cookie: X-PP-SILOVER=name%3DLIVE3.WEB.1%26silo_version%3D880%26app%3Dmppnodeweb%26TIME%3D991013976%26HTTP_X_PP_AZ_LOCATOR%3Dslcb.slc; Expires=Tue, 21 Feb 2017 10:36:51 GMT; domain=.paypal.com; path=/; Secure; HttpOnly
< Set-Cookie: X-PP-SILOVER=; Expires=Thu, 01 Jan 1970 00:00:01 GMT
< Set-Cookie: AKDC=phx-origin-www-1.paypal.com; expires=Tue, 21-Feb-2017 10:36:51 GMT; path=/; secure
< Set-Cookie: akavpau_ppsd=1487672211~id=cae8071e8da0e5fdb485811908c64fd0; path=/
< Strict-Transport-Security: max-age=63072000
<
* Closing connection #1
* SSLv3, TLS alert, Client hello (1):
* Issue another request to this URL: 'https://www.paypal.com/it/home'
* About to connect() to proxy 192.168.10.1 port 3128 (#1)
*   Trying 192.168.10.1... connected
* Establish HTTP proxy tunnel to www.paypal.com:443
> CONNECT www.paypal.com:443 HTTP/1.1
> Host: www.paypal.com:443
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Proxy-Connection: Keep-Alive
>
< HTTP/1.0 200 Connection established
<
* Proxy replied OK to CONNECT request
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* SSL re-using session ID
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSL connection using ECDHE-RSA-AES128-GCM-SHA256
* Server certificate:
*        subject: 1.3.6.1.4.1.311.60.2.1.3=US; 1.3.6.1.4.1.311.60.2.1.2=Delaware; businessCategory=Private Organization; serialNumber=3014267; C=US; postalCode=95131-2021; ST=California; L=San Jose; street=2211 N 1st St; O=PayPal, Inc.; OU=CDN Support; CN=www.paypal.com
*        start date: 2016-02-02 00:00:00 GMT
*        expire date: 2017-10-30 23:59:59 GMT
*        issuer: C=US; O=Symantec Corporation; OU=Symantec Trust Network; CN=Symantec Class 3 EV SSL CA - G3
*        SSL certificate verify ok.
> GET /it/home HTTP/1.0
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: www.paypal.com
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: Apache
< X-Recruiting: If you are reading this, maybe you should be working at PayPal instead! Check out https://www.paypal.com/us/webapps/mpp/paypal-jobs
< Paypal-Debug-Id: ef6f606ac62a4
< Cache-Control: no-cache
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< X-FRAME-OPTIONS: SAMEORIGIN
< Content-Security-Policy: default-src 'self' https://*.paypal.com https://*.paypalobjects.com https://nexus.ensighten.com 'unsafe-inline'; frame-src 'self' https://*.brighttalk.com https://*.paypal.com https://*.paypalobjects.com https://www.youtube.com/embed/ https://www.paypal-donations.com https://www.paypal-donations.co.uk https://*.qa.missionfish.org https://www.youtube-nocookie.com https://www.xoom.com https://*.pub.247-inc.net/; script-src 'self' https://*.brighttalk.com https://*.paypal.com https://*.paypalobjects.com https://www.youtube.com/iframe_api https://s.ytimg.com/yts/jsbin/ https://*.t.eloqua.com https://img.en25.com/i/elqCfg.min.js https://nexus.ensighten.com/ 'unsafe-inline' 'unsafe-eval'; connect-src 'self' https://*.paypal.com https://*.paypalobjects.com https://*.salesforce.com https://*.force.com https://*.eloqua.com https://nexus.ensighten.com https://storelocator.api.where.com https://api.paypal-retaillocator.com https://nominatim.openstreetmap.org https://www.paypal-biz.com; img-src 'self' * data:; object-src 'self' https://*.paypal.com https://*.paypalobjects.com; font-src 'self' https://*.paypalobjects.com;
< ETag: W/"6646-N9seUapd2xMK7C+gFi/cTw"
< HTTP_X_PP_AZ_LOCATOR: dcg11.slc
< Paypal-Debug-Id: ef6f606ac62a4
< Cache-Control: max-age=0, no-cache, no-store, must-revalidate
< Pragma: no-cache
< Content-Type: text/html; charset=utf-8
< DC: phx-origin-www-1.paypal.com
< X-EdgeConnect-MidMile-RTT: 3
< X-EdgeConnect-Origin-MEX-Latency: 242
< X-EdgeConnect-MidMile-RTT: 175
< X-EdgeConnect-Origin-MEX-Latency: 242
< Date: Tue, 21 Feb 2017 10:06:54 GMT
< Content-Length: 26182
< Connection: close
< Set-Cookie: cookie_check=yes; Domain=.paypal.com; Path=/; Expires=Sun, 21 Feb 2027 10:06:52 GMT; HttpOnly; Secure
< Set-Cookie: LANG=it_IT%3BIT; Domain=.paypal.com; Path=/; Expires=Tue, 21 Feb 2017 18:52:48 GMT; HttpOnly
< Set-Cookie: tsrce=mppnodeweb; Domain=.paypal.com; Path=/; Expires=Wed, 22 Feb 2017 10:06:52 GMT; HttpOnly; Secure
< Set-Cookie: x-pp-s=eyJ0IjoiMTQ4NzY3MTYxMzk0NyIsIm0iOiIwIn0; Domain=.paypal.com; Path=/; HttpOnly; Secure
< Set-Cookie: nsid=s%3A74ujkGU9eWQSC2wQM8PXHRRoHjuQmucM.0ykPY%2FAkmfXl50QcbBuCSwC7lEm1YbqKWOXxw4FicY0; Path=/; HttpOnly; Secure
< Set-Cookie: X-PP-SILOVER=name%3DLIVE3.WEB.1%26silo_version%3D880%26app%3Dmppnodeweb%26TIME%3D1024568408%26HTTP_X_PP_AZ_LOCATOR%3Ddcg11.slc; Expires=Tue, 21 Feb 2017 10:36:53 GMT; domain=.paypal.com; path=/; Secure; HttpOnly
< Set-Cookie: X-PP-SILOVER=; Expires=Thu, 01 Jan 1970 00:00:01 GMT
< Set-Cookie: AKDC=phx-origin-www-1.paypal.com; expires=Tue, 21-Feb-2017 10:36:54 GMT; path=/; secure
< Set-Cookie: akavpau_ppsd=1487672214~id=56a8294899d3c18083d0709205e7d737; path=/
< Strict-Transport-Security: max-age=63072000
<
<

richiesta che è andata a buon fine, per la causa del problema è stata correttamente individuata.

Soluzione definitiva

Per risolvere definitivamente tale anomalia (legata principalmente alla cattiva gestione, da parte di squidGuard, dei domini che contengono caratteri particolari), ho deciso di agire come segue. Poichè le blackist vengono aggiornate ogni notte in modo automatico, il file domains modificato in precedenza verrebbe continuamente sovrascritto, rendendo nulla la sostituzione di -paypal.com com con \-paypal.com. Quindi, per fare in modo che squidGuard torni a consentire definitivamente l’accesso al dominio paypal.com (e relativi sottodomini), ho deciso di creare un file domains all’interno della dir /var/lib/squidguard/db/whitelist, contenente la entry paypal.com:

root@linux-box:~# cat /var/lib/squidguard/db/whitelist/domains
paypal.com

Ho quindi modificato la configurazione di squidGuard (/etc/squid/squidGuard.conf), ridefinendo la sequenza di matching dell’ACL che si occupa del filtraggio:

acl {
        default {
                pass whitelist !aggressive !drugs !gambling !hacking !porn !proxy !redirector !spyware !suspect !violence !warez !custom
                redirect http://192.168.10.1/block.html
        }

Nella fattispecie, ho fatto in modo che venissero dapprima consentiti tutti i domini in whitelist, bloccati i domini presenti nelle blacklist ed infine consentiti tutti gli altri.

Ho quindi ricompilato le blacklist di squidGuard come visto in precedenza:

root@linux-box:~# squidGuard -d -C all 
root@linux-box:~# chown proxy:proxy -R /var/lib/squidguard/db
root@linux-box:~# squid3 -k reconfigure

ed il problema è stato definitivamente risolto.

Alla prossima.

Nagios: script bash per monitorare lo stato dei volumi RAID

Partendo dalle considerazioni fatte in questo post, ho deciso di mettere a punto uno script bash da integrare a Nagios, in modo da monitorare lo status dei volumi RAID (e dei dischi fisici annessi) a prescindere dal metodo utilizzato per l’implementazione di tale tecnologia (hardware, fake oppure software).

nagiosDi seguito riporto il suddetto script nella sua interezza:

#!/bin/bash

type=$1

subtype=$2

element=$3

usage="check_raid <--software|--fake|--hardware> [--megaraid|--mpt] [--volume|--physical|--battery]"

if [[ ! -z "$type" && "$type" =~ "software" ]];then
        okswraid=0;
        koswraid=0;
        volumes=`cat /proc/mdstat | grep md | grep active | grep -v inactive | awk '{print $1}' | wc -l`
        if [[ ! -z $volumes ]];then
                for (( v=1; v<=$volumes; v++ ))
                do
                        volume=`cat /proc/mdstat | grep md | grep active | grep -v inactive | awk '{print $1}' | sed -n "$v p"`
                        raidtype=`cat /proc/mdstat | grep md | grep active | grep -v inactive | awk '{print $4}' | sed -n "$v p"`
                        diskno=`cat /proc/mdstat | grep '[[0-9]\/[0-9]]' | awk '{print $3}' | sed -n "$v p"`
                        disksok=`echo $diskno | sed 's/\[//g' | cut -d '/' -f1`
                        diskstotal=`echo $diskno | sed 's/\]//g' | cut -d '/' -f2`
                        if [[ "$disksok" -eq "$diskstotal" ]];then
                                echo "OK: Software RAID volume $volume configured in $raidtype is OK, with $diskno disks UP"
                                ((okswraid++))
                        elif [[ "$disksok" -lt "$diskstotal" ]];then
                                echo "CRITICAL: Software RAID volume $volume configured in $raidtype is CRITICAL, with $diskno disks UP"
                                ((koswraid++))
                        fi
                done

                if [[ $koswraid -eq 0 ]];then
                        exit 0;
                else
                        exit 2;
                fi
        else
                echo "UNKNOWN: No software RAID configured"
                exit 3;
        fi

elif [[ ! -z "$type" && "$type" =~ "fake" ]];then
        bin=`/usr/bin/which dmraid`
        if [[ ! -z $bin ]];then
                result=`$bin -s`
                disksno=`$bin -r | grep -v no | wc -l`
                disksok=`$bin -r | grep ok | wc -l`
                if [[ ! -z "$result" && "$result" =~ "ok" ]];then
                        echo "OK: RAID Status is OK, with $disksok/$disksno disks OK"
                        exit 0;
                elif [[ ! -z "$result" && "$result" =~ "no raid" ]];then
                        echo "UNKNOWN: no fake RAID configured"
                        exit 3;
                else
                        echo "CRITICAL: RAID Status is KO, with $disksok/$disksno disks OK"
                        exit 2;
                fi
        else
                echo "UNKNOWN: no dmraid binary found - please install dmraid"
                exit 3;
        fi

elif [[ ! -z "$type" && "$type" =~ "hardware" ]];then
        okraid=0;
        oksmart=0;
        koraid=0;
        kosmart=0;
        if [[ ! -z "$subtype" && "$subtype" =~ "--megaraid" ]];then
                bin=`/usr/bin/which MegaCli64`
                if [[ ! -z $bin ]];then
                        if [[ ! -z "$element" && "$element" =~ "--volume" ]];then
                                result=`$bin -LDinfo -Lall -aALL | grep State | awk '{print $3}'`
                                if [[ ! -z "$result" && $result =~ "Optimal" ]];then
                                        echo "OK: RAID Volume state is $result"
                                        exit 0;
                                else
                                        echo "CRITICAL: RAID Volume state is $result"
                                        exit 2;
                                fi
                        elif [[ ! -z "$element" && "$element" =~ "--physical" ]];then
                                diskno=`$bin -PDList -aALL | grep "S.M.A.R.T alert" | wc -l`
                                for (( d=1; d<=$diskno; d++ ))
                                do
                                        result=`$bin -PDList -aALL | grep "Firmware state" | sed -n "$d p" | awk '{print $3}' | sed 's/,//g'`
                                        if [[ ! -z "$result" && $result =~ "Online" ]];then
                                                echo "RAID Status for Physical Disk number $d is OK"
                                                ((okraid++));
                                        else
                                                echo "RAID Status for Physical Disks number $d is KO"
                                                ((koraid++));
                                        fi
                                done
                                for (( d=1; d<=$diskno; d++ ))
                                do
                                        result=`$bin -PDList -aALL | grep "S.M.A.R.T alert" | sed -n "$d p" | awk '{print $8}'`
                                        if [[ ! -z "$result" && $result =~ "No" ]];then
                                                echo "S.M.A.R.T Status for Physical Disk number $d is OK"
                                                ((oksmart++));
                                        else
                                                echo "S.M.A.R.T. Status for Physical Disks number $d is KO"
                                                ((kosmart++));
                                        fi
                                done
                                if [[ $koraid -eq 0 && $kosmart -eq 0 ]];then
                                        echo "OK: RAID and S.M.A.R.T Status for all Physical Disks is OK"
                                        exit 0;
                                elif [[ $koraid -eq 0 && $kosmart -ne 0 ]];then
                                        echo "CRITICAL: S.M.A.R.T Status for some Physical Disks is KO"
                                        exit 2;
                                elif [[ $koraid -ne 0 && "$kosmart" -eq 0 ]];then
                                        echo "CRITICAL: RAID Status for some Physical Disks is KO"
                                        exit 2;
                                elif [[ $koraid -ne 0 && $kosmart -ne 0 ]];then
                                        echo "CRITICAL: RAID and S.M.A.R.T Status for some Physical Disks is KO"
                                        exit 2;
                                fi
                        elif [[ ! -z "$element" && "$element" =~ "--battery" ]];then
                                result=`$bin -AdpBbuCmd -aAll | grep "Battery State" | awk '{print $3}'`
                                if [[ ! -z "$result" && $result =~ "OK" ]];then
                                        echo "OK: RAID Controller Battery state is OK"
                                        exit 0;
                                else
                                        echo "CRITICAL: RAID Controller Battery state is $result"
                                        exit 2;
                                fi
                        else
                                echo "UNKNOWN: please specify the element to check"
                                echo $usage;
                                exit 3;
                        fi
                else
                        echo "UNKNOWN: No MegaCli64 binary found - please install MegaCli64"
                        exit 3;
                fi

        elif [[ ! -z "$subtype" && "$subtype" =~ "mpt" ]];then
                modprobe mptctl
                bin=`/usr/bin/which mpt-status`
                bin2=`/usr/bin/which lspci`
                bin3=`/usr/bin/which daemonize`
                if [[ ! -z $bin ]];then
                        if [[ ! -z $bin2 ]];then
                                controller_status=`lspci | grep MPT`
                                if [[ ! -z $controller_status ]];then
                                        if [[ ! -z $bin3 ]];then
                                                controller=`$bin -p | grep id | awk '{print $3}' | sed 's/id=//g' | sed 's/,//g'`
                                                if [[ ! -z $controller ]];then
                                                        result=`$bin -i $controller | grep OPTIMAL`
                                                        if [[ ! -z "$result" ]];then
                                                                echo "OK: RAID Status is OPTIMAL"
                                                                exit 0;
                                                        else
                                                                echo "CRITICAL: RAID Status is DEGRADED"
                                                                exit 2;
                                                        fi
                                                else
                                                        echo "UNKNOWN: MPT Controller found but no RAID configured";
                                                        exit 3;
                                                fi
                                        else
                                                echo "UNKNOWN: No daemonize binary found - please install daemonize";
                                                exit 3;
                                        fi
                                else
                                        echo "UNKNOWN: Unable to find RAID Controller";
                                        exit 3;
                                fi
                        else
                                echo "UNKNOWN: No lspci binary found - please install lspci";
                                exit 3;
                        fi
                else
                        echo "UNKNOWN: No mpt-status binary found - please install mpt-status"
                        exit 3;
                fi

        else
                echo "UNKNOWN: please specify the RAID Controller type"
                echo $usage
                exit 3;
        fi
else
        echo "UNKNOWN: please specify the RAID type"
        echo $usage
        exit 3;
fi
exit 0

Lo usage parla chiaro: il primo argomento identifica, per l’appunto, la tecnologia RAID utilizzata sul sistema target. Il secondo ed il terzo argomento, invece, dovranno essere specificati solo nel caso in cui si abbia a che fare con un RAID di tipo hardware. Nella fattispecie, essi rappresentano, rispettivamente, la tipologia di chipset utilizzata dal controller e l’oggetto di interesse della nostra query, ovvero il volume, i dischi fisici oppure la batteria (tale parametro ha senso solo se il chipset è di tipo LSI MegaRAID).

Configurazione di Nagios

Come al solito, il primo step consiste nel definire un comando che utilizzi lo script (in gergo plugin) riportato in precedenza:

# 'check_local_raid' command definition
define command{
        command_name    check_local_raid
        command_line    $USER1$/check_raid $ARG1$ $ARG2$ $ARG3$
        }

tali direttive andranno opportunamente inserite all’interno del file /etc/nagios/objects/commands.cfg.

Successivamente si potrà procedere con la definizione del servizio che si occuperà del monitoraggio vero e proprio, da aggiungere alla configurazione dell’host target, in questo caso /etc/nagios/object/locahost.cfg:

define service{
        use                             local-service         ; Name of service template to use
        host_name                       localhost
        service_description             RAID Status
        check_command                   check_local_raid!--software
        }

A questo punto non ci rimane che ricaricare la configurazione di Nagios per rendere effettive le suddette modifiche:

[root@linuxbox ~]# service nagios reload

ed abbiamo finito.

Alla prossima.

Sistemi RAID implementabili su Linux

Premessa

L’obiettivo di questo post non è quello di spiegare le diverse modalità di funzionamento del RAID (già discusse qui), ma di illustrare come sia possibile implementare tale tecnologia sulle macchine Linux.

RAID

Tipologie di sistemi RAID

Per farla breve, esistono 3 modi per realizzare quanto detto sopra:

1) Utilizzando un controller dedicato (in questo caso parliadmo di RAID hardware). Ovviamente ne esiste una vasta gamma ma ciò che li contraddistingue è il chipset di cui sono dotati (ad esempio LSI MPT, LSI MegaRAID, ecc)., dato che è proprio tramite di essi che il sistema operativo sarà in grado di interfacciarsi con i dischi (siano essi fisici o virtuali). A mio avviso, questo è il metodo più sicuro di implementazione del RAID (a patto che si tenga sotto controllo lo stato di salute dei vari elementi coinvolti, compresa la batteria di backup in dotazione al controller).

2) Avvalendosi del chipset integrato alla scheda madre (sempre che tale funzionalità sia effettivamente supportata). In tal caso parliamo di RAID ATA o fake RAID. E’ sicuramente uno dei metodi più comodi di implementazione (la creazione e gestione dei volumi avviene mediante il BIOS), ma è comunque poco affidabile (non sono rari i casi in cui tale tecnologia si è rivelata essere insufficiente, portando spesso alla perdita di tutte le informazioni presenti sugli hard drive).

3) Demandando al sistema operativo (Linux) la creazione e la gestione dei dischi logici. In questo caso parliamo di RAID software. Anche questo metodo, come quello del punto 1, è molto sicuro ed è ampiamente preferibile al fake RAID.

Tool per la gestione dei sistemi RAID hardware

A seconda della tecnologia scelta, Linux è in grado di interrogare lo stato dei dischi configurati in RAID avvalendosi di alcuni tool. Ad esempio, se si utilizza un controller dedicato e ci si vuole interagire, occorrerà prima di tutto individuare il chipset di cui è dotato e successivamente scegliere un tool in grado di interfacciarsi con esso.

Nella fattispecie, per l’indentificazione dei chipset, si può utilizzare il tool lspci:

[root@linuxbox ~]# lspci | grep LSI

oppure, in alternativa, il comando dmesg:

[root@linuxbox ~]# dmesg | grep LSI

Una volta identificato il chipset, occorrerà sincerarsi che esso sia supportato dal kernel della nostra macchina (ovvero che esiste un driver in grado di parlarci), ed in caso affermativo verificare, in seconda battuta, che tale driver (sottoforma di modulo) sia stato opportunamente caricato.

Nella fattispecie, se parliamo di un chipset LSI MPT, sarà necessario caricare il modulo mptctl mediante il seguente comando:

[root@linuxbox ~]# modprobe mptctl

In seguito si dovranno scaricare ed installare i tool daemonize ed mpt-status, il primo mandatorio per il funzionamento del secondo (se utilizzate una macchina CentOS/RHEL potete scaricarli da qui).

Una volta fatto ciò sarà possibile interrogare il controller utilizzando il seguente comando:

[root@linuxbox ~]# mpt-status -p

che ci restituirà l’ID del controller stesso e successivamente:

[root@linuxbox ~]# mpt-status -i <ID controller>

per individuare lo stato dei volumi e dei dischi fisici.

Nel caso in cui, invece, si avesse a che fare con un controller LSI MegaRAID, sarà necessario utilizzare un tool a scelta tra dmraid o MegaCli64 (anche se esistono diverse alternative, quali storcli). Sinceramente preferisco il secondo, anche se la sintassi che utilizza non è propriamente esplicativa. Solo a titolo di esempio, ecco alcune “query” (lasciatemi passare il termine) dirette al controller ed effettuate mediante MegaCli64:

[root@linuxbox ~]# MegaCli64 -AdpAllInfo -aAll

per ottenere tutte le info relative al controller stesso (stato dei volumi, dei dischi fisici, della batteria, ecc.);

[root@linuxbox ~]# MegaCli64 -AdpBbuCmd -aAll | grep "Battery State"

per individuare lo stato della batteria del controller (detta di backup), grazie alla quale è possibile preservare la configurazione del RAID anche in caso di failure della CMOS;

[root@linuxbox ~]# MegaCli64 -LDinfo -Lall -aALL | grep "State"

per avere informazioni relative ai dischi logici (volumi);

[root@linuxbox ~]# MegaCli64 -PDList -aALL

per individuare lo stato dei dischi fisici;

[root@linuxbox ~]# MegaCli64 -PDList -aALL | grep "S.M.A.R.T alert

per appurare la presenza di eventuali errori di tipo S.M.A.R.T (vedi qui per ulteriori dettagli);

[root@linuxbox ~]# MegaCli64 -PDList -aALL | grep "Firmware state"

per individuare lo stato delle repliche RAID sui dischi fisici.

Tool per la gestione dei sistemi RAID ATA

Per quanto riguarda il fake RAID, uno dei tool più diffusi per la sua gestione è sicuramente dmraid. E’ necessario precisare, inoltre, che tale tool supporta anche diversi controller hardware e per ottenere una lista esaustiva di quelli compatibili basta utilizzare il comando:

[root@linuxbox ~]# dmraid -l

il cui output sarà simile al seguente:

asr     : Adaptec HostRAID ASR (0,1,10)
ddf1    : SNIA DDF1 (0,1,4,5,linear)
hpt37x  : Highpoint HPT37X (S,0,1,10,01)
hpt45x  : Highpoint HPT45X (S,0,1,10)
isw     : Intel Software RAID (0,1,5,01)
jmicron : JMicron ATARAID (S,0,1)
lsi     : LSI Logic MegaRAID (0,1,10)
nvidia  : NVidia RAID (S,0,1,10,5)
pdc     : Promise FastTrack (S,0,1,10)
sil     : Silicon Image(tm) Medley(tm) (0,1,10)
via     : VIA Software RAID (S,0,1,10)
dos     : DOS partitions on SW RAIDs

Per ottenere lo stato del volume RAID è sufficiente lanciare il comando:

[root@linuxbox ~]# dmraid -s

il cui output sarà qualcosa del tipo:

*** Group superset isw_bigeeiijaj
--> Active Subset
name   : isw_bigeeiijaj_Volume0
size   : 312576256
stride : 128
type   : mirror
status : ok
subsets: 0
devs   : 2
spares : 0

Per lo stato dei dischi fisici, invece, occorre utilizzare la flag -r:

[root@linuxbox ~]# dmraid -r

/dev/sdc: isw, "isw_bigeeiijaj", GROUP, ok, 312581806 sectors, data@ 0
/dev/sda: isw, "isw_bigeeiijaj", GROUP, ok, 312581806 sectors, data@

Tool per la gestione dei sistemi RAID Software

Per gestire i RAID software si può utilizzare il tool mdadm o, in alternativa, nel caso in cui fosse sufficiente individuare lo stato dei dischi fisici e dei volumi, si può lanciare il comando:

[root@linuxbox ~]# cat /proc/mdstat

il cui output avrà il seguente formato:

[root@linuxbox ~]# cat /proc/mdstat
Personalities : [raid1]
md3 : active raid1 sda3[0] sdb3[1]
      511998912 blocks [2/2] [UU]
      bitmap: 0/4 pages [0KB], 65536KB chunk

md2 : active raid1 sda2[0] sdb2[1]
      1433598912 blocks [2/2] [UU]
      bitmap: 4/11 pages [16KB], 65536KB chunk

dove la stringa Personalities: indica il tipo di RAID supportato dal kernel, mentre md3 ed md2 sono i 2 volumi configurati in RAID 1 (mirroring).

Per ora è tutto. Alla prossima.

Script bash per automatizzare le query su MySQL

Scenario

Supponiamo che il vostro DBMS (MySQL) stia gestendo più database e che sia necessario effettuare delle query  “a tappeto”, ovvero su tutte le tabelle relative a ciascuno di essi (cercando, ad esempio, un determinato record oppure un pattern specifico).

bashEseguire tale operazione “a mano” può essere tedioso e soprattutto controproducente in termini di tempo. Come fare quindi? Semplice, realizzare uno scrip bash in grado di automatizzare tale attività.

Ecco il codice:

#!/bin/bash

mysql -u utente -ppassword -e 'show databases' | grep -v Database | grep -v information_schema | grep -v mysql > databases

while read line
do

        command="mysql -u utente -ppassword -e 'use $line; show tables'"
        eval $command | grep -v "Tables_in_*" > tables_$line

done < databases

num_databases=`cat databases | wc -l`

ls | grep "tables_*" > table

num_tables=`cat table | wc -l`

if [ $num_databases -eq $num_tables ];then

        for i in {1..19}
        do
                database=`cat databases | sed -n "$i p"`
                echo ".......tables for $database......."
                cat tables_"$database" | while read line
                do
                        echo $line
                        command="mysql -u utente -ppassword -e 'use $database; select * from $line LIMIT 1'"
                        echo "....Executing $command...." >> result
                        eval "$command" | tee -a result
                        echo "....End executing $command ...." >> result

                done
                echo ".......end tables for $database......."
        done

fi

Per prima cosa identifico tutti i database definiti su MySQL, escludendo quelli di default (mysql ed information_schema), formattando opportunamente l’output ( grep -v Database) e salvando i risultati all’interno del file databases:

mysql -u utente -ppassword -e 'show databases' | grep -v Database | grep -v information_schema | grep -v mysql > databases

Successivamente listo le tabelle presenti in ciascun database mediante un ciclo while che legge, riga per riga, il contenuto del file databases e, per ognuna, esegue il comando show tables:

while read line
do

        command="mysql -u utente -ppassword -e 'use $line; show tables'"
        eval $command | grep -v "Tables_in_*" > tables_$line

done < databases

Da notare come la stringa $command venga dapprima definita in modo tale da contenere il valore della variabile $line e successivamente venga eseguita sottoforma di comando mediante la direttiva eval.

Verifico, quindi, che il numero dei file tables_$line sia uguale al numero di database (e che quindi vi sia la ragionevole certezza che per ciascun database sia stato individuato il nome delle tabelle di cui è composto):

num_databases=`cat databases | wc -l` ls | grep "tables_*" > table 

num_tables=`cat table | wc -l` 

if [ $num_databases -eq $num_tables ];then

Infine, per ciascuna tabella di ciascun database, lancio la query mysql -u utente -ppassword -e ‘use $database; select * from $line LIMIT 1’, definita come stringa ed eseguita mediante eval (come visto in precedenza):

for i in {1..19}
        do
                database=`cat databases | sed -n "$i p"`
                echo ".......tables for $database......."
                cat tables_"$database" | while read line
                do
                        echo $line
                        command="mysql -u utente -ppassword -e 'use $database; select * from $line LIMIT 1'"
                        echo "....Executing $command...." >> result
                        eval "$command" | tee -a result
                        echo "....End executing $command ...." >> result

                done
                echo ".......end tables for $database......."
        done

fi

Da notare come, nel mio caso, vi sia un totale di 19 database, per cui ho utilizzato un semplice ciclo for così definito:

for i in {1..19}

Nulla però vieta di usare come upper bound la variabile $num_databases o $num_tables.

Infine rendiamo eseguibile lo scrip (che ho denominato, per semplicità, my.sh):

[root@server ~]# chmod +x my.sh

ed eseguiamolo:

[root@server ~]# ./my.sh

E’ tutto, alla prossima.

Configurazione del demone snmpd su CentOS 6

Utilizzare il protocollo SNMP per il monitoraggio dei dispositivi di rete è sempre una buona scelta, tenendo bene a mente, però, che le versioni 1 e 2 non prevedono cifratura della community string e quindi sono vulnerabili ad eventiali attacchi MITM. Inoltre, in determinate circostanze, tale protocollo può essere impiegato anche per il monitoraggio delle macchine *nix, soprattutto per ciò che concerne lo stato delle interfacce di rete ed il loro throughput.

snmpInstallazione e configurazione di snmpd

Vediamo adesso come configurare il demone snmpd su una macchina CentOS 6.

Per prima cosa occorre installare i seguenti pacchetti tramite yum:

[root@server ~]# yum install net-snmp net-snmp-utils

A questo punto passiamo alla configurazione del demone vera e propria, editando il file /etc/snmp/snmp.conf. 

Definiamo, dapprima, le utenze ed i gruppi, mediante le seguenti direttive:

com2sec local      localhost        secret
com2sec mynetwork  192.168.1.0/24 secret

group local      v2c        local
group mynetwork  v2c        mynetwork

In particolare, mediante la keyword com2sec stiamo definendo l’utente local, il cui IP/hostname sorgente dovrà essere localhost e la cui community string dovrà essere secret. Discorso analogo vale per l’utente mynetwork.

Invece, per ciò che concerne la definizione dei gruppi, la keyword da utilizzare è group, seguita dal nome del gruppo, dalla versione del protocollo SNMP (v2c) e dal nome degli utenti che ne fanno parte (local nel primo caso e mynetwork nel secondo).

Successivamente è necessario abilitare l’intera alberatura degli OID, mediante la seguente direttiva:

view all    included  .1                               80

Infine, passiamo alla definizione delle ACL per i gruppi appena creati:

#               context sec.model sec.level prefix   read  write notif
access  local     ""      any       noauth   exact   all   none none
access  mynetwork ""      any       noauth   exact   all   none none

dove la prima riga indica il significato di ciascun campo utilizzato dopo la keyword access ed il gruppo a cui l’ACL si riferisce. Dalla suddetta configurazione è facile notare come entrambi i gruppi (local e mynetwork) abbiano solo la possibilità di effettuare GET SNMP (read) ma non SET (write).

Per completezza, è possibile editare dei campi facoltativi quali syslocation e syscontact:

syslocation Italy server.vostrodominio.com
syscontact Nome Cognome <vostro.indirizzo@email.it>

Riavviamo snmpd per rendere effettive le suddette modifiche:

[root@server ~]# service snmpd restart

ed effettuiamo una query di prova, avvalendoci del tool snmpwalk:

[root@server ~]# snmpwalk -v 2c -c secret localhost

Se otterremo in output l’intera alberatura SNMP supportata dalla macchina significa che il demone sta funzionando come dovrebbe.

 Configurazione di Nagios

Per fare in modo che il nostro NMS sia in grado di monitorare lo stato ed il throughput delle interfacce di rete, occorre definire i seguenti comandi all’interno del file /etc/nagios/objects/commands.cfg:

# 'check_snmp_if_status' command definition
define command{
        command_name    check_snmp_if_status
        command_line    $USER1$/check_snmp -H $HOSTADDRESS$ -C $ARG1$ -P $ARG2$ -o $ARG3$ -r $ARG4$
        }

# 'check_local_mrtgtraf' command definition
define command{
        command_name    check_local_mrtgtraf
        command_line    $USER1$/check_mrtgtraf -F "$ARG1$" -a "$ARG2$" -w "$ARG3$" -c "$ARG4$" -a "$ARG5$"
        }

ed i seguenti servizi all’interno del file di configurazione associato alla macchina da monitorare:

define service{
        use                             local-service         ; Name of service template to use
        host_name                       localhost
        service_descripion             WAN Interface eth0 Operational Status
        check_command                   check_snmp_if_status!secret!IF-MIB::ifOperStatus.2!1
        }

define service{
        use                             local-service         ; Name of service template to use
        host_name                       localhost
        service_descripion             LAN Interface eth1 Operational Status
        check_command                   check_snmp_if_status!secret!2c!IF-MIB::ifOperStatus.3!1
        }

define service{
        use                             local-service   ; Name of service template to use
        host_name                       localhost
        service_descripion             WAN Interface eth0 Bandwidth Usage
        check_command                   check_local_mrtgtraf!/var/www/mrtg/localhost_2.log!AVG!100000000,200000000!110000000,120000000!10
        }

define service{
        use                             local-service   ; Name of service template to use
        host_name                       localhost
        service_descripion             LAN Interface eth1 Bandwidth Usage
        check_command                   check_local_mrtgtraf!/var/www/mrtg/localhost_3.log!AVG!100000000,200000000!110000000,120000000!10
        }

Nella fattispecie, il monitoraggio del throughput viene realizzato mediante il plugin check_mrtgtraf, il cui scopo è quello di analizzare i file di log generati da MRTG (vedi questo post per ulteriori dettagli).

Ricarichiamo la configurazione di Nagios per rendere effettive le suddette modifiche:

[root@server ~]# service nagios reload

ed abbiamo finito.

Alla prossima.

CentOS 6, Nagios e NagVis: creazione di mappe personalizzate per l’attività di monitoring

Da qualche anno ormai sono solito postare diversi articoli riguardanti il mio NMS preferito, ovvero Nagios (nella versione core). Qualcuno di voi obietterà dicendo che c’è di meglio sul mercato, soprattutto per ciò che concerne la facilità/rapidità di utilizzo e configurazione. Personalmente credo che, utilizzando le terze parti che hanno reso celebre il software in questione, è possibile raggiungere livelli di usabilità e prestazioni del tutto simili a quelle degli NMS concorrenti e di ultima generazione (vedi, ad esempio, Icinga).

nagvis

In particolare, la mia infrastruttura di monitoraggio tipo si compone dei seguenti elementi:

1) Nagios core;

2) PNP4Nagios per la graficizzazione dei risultati ottenuti mediante i check;

2) Un sistema per la ricezione delle trap SNMP (snmptrapd + snmptt per la loro traduzione) convertite all’occorrenza in check passivi mediante il plugin submit_check_result;

3) Un tool per il monitoraggio delle macchine Windows mediante polling (NRPE + check_nrpe);

4) NSCA insieme ad NSClient++ per la ricezione dei check passivi provenienti dalle macchine Windows;

5) Swatch + NRDP per la conversione dei nuovi eventi registrati all’interno dei file di log (monitorati in tempo reale da swatch) in check passivi;

6) MRTG per il monitoraggio delle prestazioni della rete (throughput di picco e medio) e, all’occorrenza, per tenere sotto controllo le performance di Nagios (vedi questo articolo per ulteriori dettagli);

7) Event handlers vari ed eventuali per la risoluzione automatica dei problemi segnalati da Nagios;

8) NagVis per la creazione di mappe personalizzate, contenenti tutti gli elementi della nostra infrastruttura che vogliamo tenere sotto controllo (con grado di dettaglio libero a piacere).

In questo post tratterò, per l’appunto, l’installazione e la configurazione di NagVis.

Installazione e configurazione dell’event broker

Per prima cosa occorre scaricare ed installare sul nostro sistema il cosiddetto event broker, ovvero un applicativo che farà da “tramite” (lasciatemi passare il termine) tra Nagios e NagVis. Nella fattispecie, esso “interrogherà” Nagios sullo stato di un host o di un servizio e girerà il risultato a NagVis.

L’event broker di nostro interesse è mklivestatus (creato da Mathias Kettner, lo stesso autore di Check_Mk), la cui pagina ufficiale è questa.

Possiamo dunque scaricarlo:

[root@linuxbox ~]# cd /usr/local/

[root@linuxbox local]# wget 'https://mathias-kettner.de/download/check_mk-1.2.7i3p5.tar.gz'

decomprimerlo:

[root@linuxbox local]# tar -xvf check_mk-1.2.7i3p5.tar.gz

ed installarlo:

[root@linuxbox local]# cd check_mk-1.2.7i3p5 && ./configure && make && make install

A questo punto creiamo la directory rw all’interno di /var/spool/nagios, assegnandole il giusto owner:

[root@linuxbox local]# cd /var/spool/nagios && mkdir rw

[root@linuxbox nagios]# chown nagios:nagios rw

In questo modo il nostro event broker potrà salvare le informazioni, ricavate dall’NMS, all’interno dell’apposito file /var/spool/nagios/rw/live.

Ora possiamo integrare il suddetto applicativo a Nagios, modificandone il file di configurazione (/etc/nagios/nagios.cfg) come segue:

event_broker_options=-1

broker_module=/usr/local/lib/mk-livestatus/livestatus.o /var/spool/nagios/rw/live

Passiamo adesso a NagVis.

Installazione e configurazione di NagVis

Prima di tutto è necessario installare le dipendenze indispensabili al suddetto applicativo:

[root@linuxbox ~]# yum install php-gd php-mbstring php-pdo graphviz graphviz-graphs perl-GraphViz graphviz-doc rsync

A questo punto sarà possibile installare NagVis puntando a questo link. Esso si riferisce all’ultima versione stabile (ovvero la 1.8.5).

[root@linuxbox ~]# cd /usr/local/ && wget http://www.nagvis.org/share/nagvis-1.8.5.tar.gz

Una volta completato il download occorre decomprimere l’archivio:

[root@linuxbox local]# tar -xvf nagvis-1.8.5.tar.gz

e, successivamente, passare all’installazione vera e propria dell’applicativo:

[root@linuxbox local]# cd nagvis-1.8.5 && ./install.sh

Inoltre, occorre configurarlo come segue:

[root@linuxbox nagvis]# nano etc/nagvis.ini.php

[backend_live_1]
backendtype="mklivestatus"
socket="unix:/var/spool/nagios/rw/live"

Riavviamo httpd:

[root@linuxbox nagvis]# service nagios reload

e puntiamo all’indirizzo dell’interfaccia Web di NagVis:

http://ipserver/nagvis

Infine, dopo esserci loggati utilizzando le credenziali di default (admin/admin), possiamo modificarle ed installare delle immagini utili alla creazione delle nostre mappe attingendo da questo e quest’altro sito.

Il risultato finale sarà simile al seguente:

nagvis_vmwareIl post termina qui, alla prossima.

CentOS 6 e PHP 5.3.3: cifratura del codice sorgente mediante BLENC (Blowfish Encoder for PHP source scripts)

A quanti di voi sarà capitato di dover cifrare del codice PHP scritto di vostro pugno, magari perchè contenente informazioni sensibili, quali, ad esempio, username e password di accesso al database?

Ebbene, un metodo semplice per ottenere quanto sopra consiste nell’installare il modulo PHP BLENC (che è ancora in versione beta – qui trovate il manuale). Tale operazione può essere effettuata in modo semiautomatico utilizzando il tool pecl presente sulla nostra macchina.

PHPPrima di procedere, è necessario verificare che il suddetto applicativo sia già installato, digitando il comando:

[root@linuxbox ~]# which pecl

il cui output dovrebbe essere:

/usr/bin/pecl

Successivamente, potremo procedere con l’installazione vera e propria del modulo BLENC, lanciando il comando:

[root@linuxbox ~]# pecl install -f blenc

A questo punto potremo creare il file blenc.ini da posizionare all’interno della dir /etc/php.d, il cui contenuto dovrà  essere simile al seguente:

; Enable blenc extension module
extension=blenc.so

All’interno del file /etc/php.ini, utilizzando la entry blenc.key_file, possiamo definire il percorso in cui trovare le chiavi per decifrare gli scrip criptati, ovvero:

[blenc]

blenc.key_file = /usr/local/etc/blenckeys

Ora passiamo alla creazione del file encrypt.php, il cui contenuto dovrà essere:

<?php

$file_to_crypt=file_get_contents("security.php");

$key=blenc_encrypt($file_to_crypt, "connect.php");

$key_file = ini_get('blenc.key_file');

file_put_contents($key_file, $key."\n", FILE_APPEND);

?>

il quale ci consentirà di cifrare gli scrip di nostro interesse.

In particolare, security.php contiene il codice sorgente che vogliamo criptare, connect.php sarà il nostro file cifrato e la chiave generata mediante la funzione blenc_encrypt() verrà salvata all’interno dell’apposito file /usr/local/etc/blenckeys, ricavato mediante il parsing della direttiva blenc.key_file presente in /etc/php.ini.

Da notare che all’interno della funzione file_put_contents(), il secondo argomento contiene il carattere \n (newline), poichè per il corretto funzionamento del modulo è necessario che per ogni riga sia presente una sola chiave (dove ogni chiave si riferisce univocamente ad un file cifrato). Tale “accortezza” non è presente all’interno del manuale ufficiale.

Come ultimo step riavviamo httpd:

[root@linuxbox ~]# service httpd reload

ed abbiamo finito.

Alla prossima.

Nagios e CentOS 6: tuning dei service check timeout

In questo post vi ho parlato di come configurare Nagios affinchè riesca a monitorare lo stato degli aggiornamenti relativi ad una macchina Windows Server 2008 R2.

Per qualche tempo tutto ha funzionato correttamente, fino a quando il servizio in questione ha cominciato a restituirmi dei timeout. Aver ridotto gli intervalli dei check non ha portato i risultati sperati, per cui ho dovuto armarmi di pazienza ed iniziare a fare un po’ di sano troubleshooting.

nagiosProblema

Dopo l’uscita degli ultimi sistemi operativi di casa Microsoft (8, 10, Server 2012, Server 2012 R2), la verifica degli aggiornamenti relativi a Windows 7, Server 2008 e Server 2008 R2 (per i quali il supporto è ancora attivo) è diventato un processo lento e macchinoso, probabilmente a causa della minore priorità data agli OS in questione. Ecco la causa principale dei timeout di cui sopra. Come risolvere dunque? Procediamo utilizzando un metodo (quasi) infallibile, ovvero il divide et impera.

Step 1: verifica del timeout associato al comando check_nrpe

Il tool check_nrpe, utilizzato per interrogare lo stato della macchina Windows, prevede l’uso (facoltativo) della flag -t, utile per la definizione del tempo di timeout (che per default è pari a 10 secondi). Per questo motivo ho fatto in modo che il comando check_WMI_windows_updates prevedesse la possibilità di specificare un tempo di timeout libero a piacere (-t $ARG1$):

# nagios-WMI-windows-updates check command definition

define command {
        command_name    check_WMI_windows_updates
        command_line    /usr/lib64/nagios/plugins/check_nrpe -H $HOSTADDRESS$ -t $ARG1$ -c get_windows_updates
        }

Nella fattispecie, il servizio che si avvale del suddetto comando ha un tempo di timeout pari a 600 secondi, come riportato di seguito:

define service{
        use                             generic-service         ; Name of service template to use
        host_name                       Windows-Machine
        service_description             query WMI Updates for Microsoft Windows Machine
        check_command                   check_WMI_windows_updates!600
        normal_check_interval           120
        }

Esso deve coincidere con il timeout del comando get_windows_updates definito all’interno del file \Pugins\V2\V2_nrpe_commands.cfg, il cui contenuto sarà:

command[get_windows_updates]=cscrip.exe //nologo //T:600 c:\nrpe\plugins\v2\check_windows_updates.wsf /w:0 /c:1

Il suddetto timeout va definito anche all’interno del file bin\nrpe.cfg, nel modo seguente:

command_timeout= 600

Tutte queste modifiche erano già state opportunamente trattate nell’ambito del mio post originale, ma ho ritenuto comunque utile rammentarle.

Step 2: verifica del timeout associato ai servizi di Nagios

Fortunatamente, l’NMS in questione ci consente di definire un tempo di timeout “globale” per i check dei servizi definiti dall’utente. Esso è presente all’interno del file /etc/nagios/nagios.cfg e la direttiva di nostro interesse è service_check_timeout da impostare come segue:

service_check_timeout=600

Riavviamo quindi Nagios per rendere effettive le modifiche appena apportate:

[root@linuxbox ~]# service nagios reload

Step 3: verifica dei timeout delle NAT translations

L’ultima fase di troubleshooting consiste nella verifica dei timeout associati alle NAT translations del router. Il dispositivo in questione è un Cisco 877 e per visualizzare le informazioni di nostro interesse occorre utilizzare il comando:

sh ip nat translations verbose

il cui output sarà simile al seguente:

extended, timing-out, use_count: 0, entry-id: 427758, lc_entries: 0
tcp 78.13.12.241:443      192.168.4.2:443       ---                   ---
    create 2w0d, use 00:00:51 timeout:300000, timing-out,
    flags:

Come si può notare, il timeout di default per le connessioni TCP è pari a 300000 ms (300 secondi ovvero 5 minuti), ergo dobbiamo incrementarlo fino a 600000 per allinearlo alla configurazione di Nagios. Per fare ciò è sufficiente lanciare il comando:

ip nat translation tcp-timeout 600

Salviamo la configurazione del router mediante un copy run start ed i timeout del servizio spariranno come per magia.

Il post termina qui, alla prossima.

CentOS 6: gestione delle periferiche removibili mediante UDEV

Scenario

Macchina CentOS 6 dotata di 2 dischi rigidi, ovvero:

1) /dev/sda dove è presente la partizione di boot (sda1) e quella di root (sda2);

2) /dev/sdb che consta di un’unica partizione dedicata al salvataggio di dati.

CentOSProblema

Collegando una memoria flash di tipo USB (che funge da dongle per un applicativo in esecuzione sul server) essa viene inizialmente mappata come /dev/sdc. Dopo un riavvio della macchina, però, il kernel name assegnato alla stessa diventa /dev/sda e di conseguenza i 2 dischi rigidi vengono mappati come /dev/sdb e /dev/sdc. Ciò, fortunatamente, non va ad inficiare il funzionamento del server, in quanto il file /etc/fstab contiene gli UUID (univoci e soprattutto statici) assegnati a ciascuna partizione (anzichè il kernel name che, come abbiamo visto, può variare).

Nel mio caso, però, esiste un problema: poichè utilizzo uno specifico tool per monitorare lo stato delle partizioni, le quali vengono interrogate mediante il loro kernel name, dovrei modificare tale parametro di volta in volta, distinguendo il caso in cui i dischi rigidi vengono mappati in modo “standard”, ovvero come /dev/sda e /dev/sdb, dal caso in cui vengono riconosciuti come /dev/sdb e /dev/sdc (con la memoria flash che fa le veci di /dev/sda). Ergo, devo fare in modo che la memoria flash venga mappata sempre e comunque come /dev/sdd.

Soluzione

Quanto sopra può essere realizzato configurando opportunamente udev. Tale applicativo si basa su alcuni file di configurazione, dislocati su 2 directory differenti, ovvero:

1) /lib/udev/rules.d/ che contiene i file di configurazione di default (non vanno editati);

2) /etc/udev/rules.d che contiene i file di configurazione “customizzabili” dall’utente (il cui contenuto ha una maggiore priorità rispetto a quello dei file di default, “scavalcandoli” all’occorrenza).

Tutti i suddetti file vengono dati in pasto ad udev seguendo un ordine crescente dettato esclusivamente dal loro filename. Da ciò si capisce come mai il contenuto tipico della directory /etc/udev/rules.d è simile al seguente:

[root@linuxbox ~]# ls /etc/udev/rules.d/
60-pcmcia.rules  70-persistent-cd.rules    90-hal.rules
60-fprint-autosuspend.rules  60-raw.rules     70-persistent-net.rules  90-alsa.rules                98-kexec.rules

dove le direttive presenti nel file 60-pcmcia.rules vengono lette (ed eseguite) prima di quelle relative a 70-persistent-cd.rules.

Poichè vogliamo che il file contenente le nostre direttive custom venga valutato per primo, dobbiamo nominarlo come 10-local.rules. Creiamolo quindi utilizzando il comando:

[root@linuxbox ~]# touch /etc/udev/rules.d/10-local.rules

per poi popolarlo come vi indicherò più avanti.

Dopo aver creato il suddetto file, occorre individuare le caratteristiche tipiche di ciascun disco rigido e della memoria flash, utilizzando il comando:

[root@linuxbox ~]# udevadm info -a -n /dev/sdXY

dove X è la lettera che identifica il device ed Y (facoltativo) è il numero di partizione.

Ad esempio, per /dev/sda possiamo utilizzare il comando:

[root@linuxbox ~]# udevadm info -a -n /dev/sda

il cui output sarà simile al seguente:

custom logging function 0x7f90ec575030 registered
udevadm[29910]: custom logging function 0x7f90ec575030 registered
selinux=1
udevadm[29910]: selinux=1
calling: info
udevadm[29910]: calling: info
device 0x7f90ec599460 has devpath '/devices/pci0000:00/0000:00:0b.0/host0/target0:0:0/0:0:0:0/block/sda'
udevadm[29910]: device 0x7f90ec599460 has devpath '/devices/pci0000:00/0000:00:0b.0/host0/target0:0:0/0:0:0:0/block/sda'

Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '/devices/pci0000:00/0000:00:0b.0/host0/target0:0:0/0:0:0:0/block/sda':
    KERNEL=="sda"
    SUBSYSTEM=="block"
    DRIVER==""
    ATTR{range}=="16"
    ATTR{ext_range}=="256"
    ATTR{removable}=="0"
    ATTR{ro}=="0"
    ATTR{size}=="976773168"
    ATTR{alignment_offset}=="0"
    ATTR{discard_alignment}=="0"
    ATTR{capability}=="52"
    ATTR{stat}==" 7302543  1320445 841562942 71451185  6119635 28157362 271395642 272451897        0 51376878 343882883"
    ATTR{inflight}=="       0        0"

device 0x7f90ec59ff90 has devpath '/devices/pci0000:00/0000:00:0b.0/host0/target0:0:0/0:0:0:0'
udevadm[29910]: device 0x7f90ec59ff90 has devpath '/devices/pci0000:00/0000:00:0b.0/host0/target0:0:0/0:0:0:0'
  looking at parent device '/devices/pci0000:00/0000:00:0b.0/host0/target0:0:0/0:0:0:0':
    KERNELS=="0:0:0:0"
    SUBSYSTEMS=="scsi"
    DRIVERS=="sd"
    ATTRS{device_blocked}=="0"
    ATTRS{type}=="0"
    ATTRS{scsi_level}=="6"
    ATTRS{vendor}=="ATA     "
    ATTRS{model}=="TOSHIBA HDWJ105 "
    ATTRS{rev}=="AX00"
    ATTRS{state}=="running"
    ATTRS{timeout}=="30"
    ATTRS{eh_timeout}=="10"
    ATTRS{iocounterbits}=="32"
    ATTRS{iorequest_cnt}=="0xd13eaf"
    ATTRS{iodone_cnt}=="0xcfd529"
    ATTRS{ioerr_cnt}=="0x1e"
    ATTRS{modalias}=="scsi:t-0x00"
    ATTRS{evt_media_change}=="0"
    ATTRS{evt_inquiry_change_reported}=="0"
    ATTRS{evt_capacity_change_reported}=="0"
    ATTRS{evt_soft_threshold_reached}=="0"
    ATTRS{evt_mode_parameter_change_reported}=="0"
    ATTRS{evt_lun_change_reported}=="0"
    ATTRS{dh_state}=="detached"
    ATTRS{queue_depth}=="31"
    ATTRS{queue_ramp_up_period}=="120000"
    ATTRS{queue_type}=="simple"
    ATTRS{unload_heads}=="0"

device 0x7f90ec5a1b20 has devpath '/devices/pci0000:00/0000:00:0b.0/host0/target0:0:0'
udevadm[29910]: device 0x7f90ec5a1b20 has devpath '/devices/pci0000:00/0000:00:0b.0/host0/target0:0:0'
  looking at parent device '/devices/pci0000:00/0000:00:0b.0/host0/target0:0:0':
    KERNELS=="target0:0:0"
    SUBSYSTEMS=="scsi"
    DRIVERS==""

device 0x7f90ec5b3e10 has devpath '/devices/pci0000:00/0000:00:0b.0/host0'
udevadm[29910]: device 0x7f90ec5b3e10 has devpath '/devices/pci0000:00/0000:00:0b.0/host0'
  looking at parent device '/devices/pci0000:00/0000:00:0b.0/host0':
    KERNELS=="host0"
    SUBSYSTEMS=="scsi"
    DRIVERS==""

device 0x7f90ec595fb0 has devpath '/devices/pci0000:00/0000:00:0b.0'
udevadm[29910]: device 0x7f90ec595fb0 has devpath '/devices/pci0000:00/0000:00:0b.0'
  looking at parent device '/devices/pci0000:00/0000:00:0b.0':
    KERNELS=="0000:00:0b.0"
    SUBSYSTEMS=="pci"
    DRIVERS=="ahci"
    ATTRS{vendor}=="0x10de"
    ATTRS{device}=="0x0ab4"
    ATTRS{subsystem_vendor}=="0x1043"
    ATTRS{subsystem_device}=="0x83e2"
    ATTRS{class}=="0x010185"
    ATTRS{irq}=="25"
    ATTRS{local_cpus}=="f"
    ATTRS{local_cpulist}=="0-3"
    ATTRS{modalias}=="pci:v000010DEd00000AB4sv00001043sd000083E2bc01sc01i85"
    ATTRS{numa_node}=="-1"
    ATTRS{enable}=="1"
    ATTRS{broken_parity_status}=="0"
    ATTRS{msi_bus}==""

device 0x7f90ec5a5200 has devpath '/devices/pci0000:00'
udevadm[29910]: device 0x7f90ec5a5200 has devpath '/devices/pci0000:00'
  looking at parent device '/devices/pci0000:00':
    KERNELS=="pci0000:00"
    SUBSYSTEMS==""
    DRIVERS==""

Discorso simile vale per la partizione 1 del disco /dev/sda:

[root@linuxbox ~]# udevadm info -a -n /dev/sda1

il cui output sarà simile a:

custom logging function 0x7ff9331c9030 registered
udevadm[30106]: custom logging function 0x7ff9331c9030 registered
selinux=1
udevadm[30106]: selinux=1
calling: info
udevadm[30106]: calling: info
device 0x7ff9331ed460 has devpath '/devices/pci0000:00/0000:00:0b.0/host0/target0:0:0/0:0:0:0/block/sda/sda1'
udevadm[30106]: device 0x7ff9331ed460 has devpath '/devices/pci0000:00/0000:00:0b.0/host0/target0:0:0/0:0:0:0/block/sda/sda1'

Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '/devices/pci0000:00/0000:00:0b.0/host0/target0:0:0/0:0:0:0/block/sda/sda1':
    KERNEL=="sda1"
    SUBSYSTEM=="block"
    DRIVER==""
    ATTR{partition}=="1"
    ATTR{start}=="2048"
    ATTR{size}=="1024000"
    ATTR{alignment_offset}=="0"
    ATTR{discard_alignment}=="0"
    ATTR{stat}=="    2379      166   368458    10840       34       49      178     1663        0    11039    12484"
    ATTR{inflight}=="       0        0"

In particolare, utilizzeremo le informazioni riportate come attributi (ATTR) per identificare nel modo più preciso possibile il device/partizione su cui applicare le nostre regole.

Detto ciò, procediamo con la stesura del contenuto relativo al file 10-local.rules, che dovrà essere simile al seguente:

KERNEL=="sd?1", SUBSYSTEM=="block", ATTR{size}=="3915639", NAME="sdd1"
KERNEL=="sd*", SUBSYSTEM=="block", ATTR{size}=="3915776", ATTR{capability}=="53", NAME="sdd"
KERNEL=="sdb", SUBSYSTEM=="block", ATTR{size}=="976773168", ATTR{capability}=="52", NAME="sda"
KERNEL=="sdb1", SUBSYSTEM=="block", ATTR{size}=="1024000", NAME="sda1"
KERNEL=="sdb2", SUBSYSTEM=="block", ATTR{size}=="975747072", NAME="sda2"
KERNEL=="sdc", SUBSYSTEM=="block", ATTR{size}=="1953525168", ATTR{capability}=="52", NAME="sdb"
KERNEL=="sdc1", SUBSYSTEM=="block", ATTR{size}=="1953520002", NAME="sdb1"

La prima direttiva fa in modo che la partizione della memoria flash (con dimensione pari a 3915639 byte) venga rinominata in sdd1. La seconda direttiva, invece, agisce direttamente sul device, rinominandolo in sdd. Da notare che tutti i campi che contengono le condizioni da matchare per l’identificazione del dispositivo/partizione si avvalgono dell’operatore ==, mentre quelle che agiscono su di essi contengono l’operatore di assegnazione, ovvero =. Inoltre, nell’ambito delle suddette direttive, si fa uso dei caratteri speciali ? e *, con il primo che identifica un solo carattere alfanumerico, e * che identifica qualsiasi occorrenza di caratteri alfanumerici (anche nel caso in cui esse siano pari a 0).

Le rimanenti direttive, stilate sulla falsariga della prima, fanno sì che i dischi rigidi vengano rinominati rispettivamente in /dev/sda e /dev/sdb. Ovviamente tale operazione è da intendersi solo ed esclusivamente nel caso in cui, durante la fase di boot della macchina, la memoria flash sia già collegata ad una porta USB della stessa.

Non ci rimane che testare “in place” (e quindi senza reboot) le suddette regole lanciando il comando:

[root@linuxbox ~]# udevadm test /sys/block/sdX

per i device e:

[root@linuxbox ~]# udevadm test /sys/block/sdX/sdXY

per le parizioni, seguito da un:

[root@linuxbox ~]# ls -ilah /dev

per appurare che i dispositivi siano stati effettivamente mappati secondo le nostre necessità.

Per ora è tutto. A presto.