Pillole di Unicode

Unicode associa un numero univoco ad ogni carattere,
indipententemente dalla piattaforma,
indipententemente dal programma,
indipententemente dalla lingua.

 

I caratteri prima di Unicode

Fondamentalmente i computer gestiscono solo numeri. Essi memorizzano lettere ed altri caratteri assegnando un numero ad ognuno di essi. Prima che Unicode fosse inventato, esistevano centinaia di sistemi diversi, chiamati codifiche (encodings), per assegnare questi numeri. Queste prime codifiche di caratteri erano limitate e non contenevano abbastanza caratteri per coprire tutte le lingue del mondo. Anche per una singola lingua come l’inglese, un’unica codifica non era adeguata per descrivere tutte le lettere, segni di interpunzione e simboli tecnici di uso comune.

Le prime codifiche di caratteri inoltre confliggevano le une con le altre. Vale a dire, due codifiche potevano utilizzare lo stesso numero per due caratteri diversi o, viceversa, due numeri diversi per codificare lo stesso carattere. Quindi, quando i dati passavano da un computer all’altro o tra diversi sistemi di codifica, i dati rischiavano di venire corrotti.

I caratteri Unicode

Unicode ha cambiato tutto questo!

Lo Standard Unicode associa un numero univoco ad ogni carattere, indipendentemente dalla piattaforma, dal dispositivo, dall’applicazione o dalla lingua che vengono usati. È stato adottato da tutti i produttori di software moderni ed ora consente ai dati di essere trasportati attraverso molte differenti piattaforme, dispositivi e applicazioni senza corruzione. Il supporto di Unicode costituisce il fondamento per la rappresentazione di lingue e simboli in tutti i principali sistemi operativi, motori di ricerca, browser, computer portatili e smartphone – più Internet ed il World Wide Web (URLs, HTML, XML, CSS, JSON, etc.). Supportare Unicode è il modo migliore per implementare lo standard ISO/IEC 10646.

Lo standard ISO/IEC 10646

L’Insieme Universale di Caratteri Codificati [Universal Coded Character Set (UCS)] è un insieme standard di caratteri definiti dallo International Standard ISO/IEC 10646, Information technology — Universal Coded Character Set (UCS) (più successive modifiche), che è la base di di molte codifiche caratteri. L’ultima versione contiene oltre 136.000 caratteri astratti, ciascuno identificato con un nome non ambiguo e un numero intero detto il suo punto codice (code point). Questo standard ISO/IEC 10646 è manutenuto in congiunzione con lo standard Unicode ed entrambi sono identici codice per codice.

Ma ci sono delle differenze tra ISO/IEC 10646 e Standard Unicode e riguardano più l’ambito applicativo.

ISO/IEC 10646 è fondamentalmente una tabella, mentre Unicode si occupa anche delle regole da rispettare per eseguire il confronto di stringhe (collation), regole per la pronuncia dipendente dal contesto (text normalization) e altri aspetti.

[Wikipedia]

L’avvento dello Standard Unicode e la disponibilità di strumenti che lo supportano sono tra le più importanti tendenze della tecnologia software globale.

Sul Consorzio Unicode

Il consorzio Unicode è un’organizzazione no profit, esentasse negli USA (501(c)(3)) che è stata fondata per sviluppare, estendere e promuovere l’uso dello standard Unicode e i relativi standard di globalizzazione che specificano la rappresentazione del testo in prodotti software moderni e altri standard.

Il Consorzio viene supportato finanziariamente attraverso abbonamenti e donazioni. L’appartenenza al Consorzio Unicode è aperto alle organizzazioni e agli individui che, ovunque nel mondo, supportino lo standard Unicode e desiderino partecipare nella sua estensione ed implementazione. Tutti sono invitati a contribuire al supporto dell’importante lavoro del Consorzio facendo una donazione.

Maggiori informazionisi trovano sul sito di Unicode.

Pillole di MySQL: comportamento dei campi timestamp

mysqlNella dichiarazione di un campo di tipo timestamp viene per default abilitata la valorizzazione automatica all’istante corrente del campo quando inseriamo un nuovo record. Ad esempio, se in una tabella attivita abbiamo un campo data dichiarato come timestamp, quando inseriamo un nuovo record il campo verrà popolato anche senza la sua presenza esplicita nell’istruzione SQL. Supponiamo allora di avere questa tabella attivita così definita:

 

create table attivita1 (
   id int(10) auto_increment primary key,
   id_commessa int(10) not null,
   descrizione varchar(100) not null,
   data timestamp not null
);

Ora, se inserisco un record senza citare esplicitamente il campo data

insert into attivita (id_commessa, descrizione) values (123, 'Nuovo incarico');

nel campo data avrò il valore dell’istante in cui è stata eseguita l’istruzione (un po’ allo stesso modo con cui viene popolato un campo auto_increment).

Il problema (dal mio punto di vista per questa particolare applicazione) è che  lo stesso comportamento si verifica anche per un update:

update attività set id_commessa=321 where id=100

Anche il campo data, non esplicitamente citato nell’istruzione, cambierà. A volte ciò non è desiderabile. Per evitare questo comportamento dobbiamo modificare la tabella con una istruzione DDL:

ALTER TABLE attivita
CHANGE data 
data TIMESTAMP NOT NULL
DEFAULT CURRENT_TIMESTAMP

Così facendo non ho questo fastidioso (in questo caso) effetto collaterale.

Se non si dichiara esplicitamente il comportamento del default in fase di creazione, MySQL aggiungerà  automaticamente anche questa direttiva:

DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

che causerà il comportamento indesiderato durante l’aggiornamento.

 

 

Martorèo

È un vocabolo del dialetto veneto, almeno nella mia zona di origine che si situa nel baricentro tra le città di Venezia, Padova e Treviso. Amici della provincia di Treviso mi segnalano che da quelle parti verso la Pedemontana si chiami MazariòlMathariòl, pronunciato con il suono della theta greca (la fricativa dentale sorda dell’alfabeto fonetico internazionale, denotata con la lettera θ).

Questo termine di cui voglio parlare non è la versione dialettale della parola martorello, che si trova nel Dizionario della Crusca (ma non si trova nel Devoto-Oli, per esempio), il cui significato e uso sono del tutto estranei alla tradizione veneta. Si tratta invece del nome con cui ci si riferisce ad una specie di demone, o di folletto, che i contadini veneti ritenevano responsabile di scherzi ai loro danni, come ad esempio la sparizione di attrezzi di lavoro o di altri oggetti di uso quotidiano.

Nella costante commistione sincretistica esistente nella mia terra tra queste rappresentazioni pagane e il cattolicesimo, c’è chi per rimediare all’impossibilità di ritrovare le cose perdute si affidava a Sant’Antonio da Padova recitando i cosiddetti “Sequeri”, dal latino “Si quaeris” (se cerchi) che è l’incipit della preghiera “Si quæris miracula” [Fonte]. Miracolosamente l’oggetto cercato faceva la sua comparsa, di solito in un luogo in cui si poteva giurare di aver guardato più volte. Le mie nonne mi hanno assicurato, per esempio, che la cosa funzionava.

A parte la divertente circostanza che il termine query, che in Informatica si usa così abbondantemente per indicare l’interrogazione di un database, tragga origine proprio dall’equivalente del latino cercare,  e la presenza di demoni anche in informatica (sono, soprattutto in ambiente Unix quei programmi che sono in costante esecuzione per tutto il tempo di accensione della macchina e ai quali sono associati dei servizi in ascolto: web server, mail server eccetera), l’accezione che io ho dato al martoreo (lo scrivo in dialetto) è quella di bug del software insidioso e difficile da scovare.

Mi sono trovato molte volte infatti di fronte ad un malfunzionamento del software la cui causa è particolarmente difficile da individuare: se si legge il codice sembra che la sua esecuzione non debba portare al malfunzionamento presente in quel momento. Cioè sembra tutto corretto ma il programma sbaglia. Ecco, ho da tanti anni battezzato questa situazione con una locuzione tratta dalla mia tradizione contadina: è colpa del martorèo, il folletto che in qualche modo agisce su programmi e dati per creare un malfunzionamento. Non ho trovato nessun altro che usasse questo curioso vocabolo per descrivere un bug difficile, non so se considerarlo un mio conio. Però quando lo uso e lo spiego per la prima volta al mio uditorio, tutti rimangono molto divertiti dalla storia.

Installazione di due versioni di PHP + Apache

Ho la necessità di lavorare alternativamente con PHP 5.6 e PHP 7.2 per due clienti.

Siccome parto da PHP5.6,  occorre installare PHP7 e il modulo Apache per PHP7 e intervenire in configurazione per selezionare l’uno o l’altro a seconda del lavoro che devo fare.

  1. Installazione di PHP7.2:
    $ sudo apt-get install php7.2 php7.2-mysql php7.2-ldap php7.2-cli
    
    $ sudo apt-get --purge autoremove -y
  2. Installazione del modulo Apache per PHP
    $ sudo apt-get install -y libapache2-mod-php7.2
  3. attivazione dell’alternativa client php7.2
    $ sudo update-alternatives --set php /usr/bin/php7.2
    
    $ php -v
    
    PHP 7.2.5-1+ubuntu16.04.1+deb.sury.org+1 (cli) (built: May 5 2018 04:59:13) ( NTS )
    
    Copyright (c) 1997-2018 The PHP Group
    
    Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    
     with Zend OPcache v7.2.5-1+ubuntu16.04.1+deb.sury.org+1, Copyright (c) 1999-2018, by Zend Technologies
    
     with Xdebug v2.6.0, Copyright (c) 2002-2018, by Derick Rethans
  4. configuazione di Apapche perché utilizzi PHP7.2 anziché il 5.6
    $ sudo a2dismod php5.6
    
    $ sudo a2enmod php7.2
    
    $ service apache2 restart

 

That’s all folks

 

Upgrade Ubuntu da 15.04 a 16.04 LTS Dapper Drake

Ho aggiornato il mio Ubuntu 15.04 alla 16.04 LTS Dapper Drake, rimanendo in attesa dell’8 luglio per poter ulteriormente aggiornare alla 18.04 LTS Bionic Beaver

Sono successi alcuni inconvenienti, non gravissimi, che elenco:

MySQL non parte più.

In questo caso ho dovuto reinstallare mysql-server e aggiornare il file di configurazione di Apparmor che non consentiva a MySQL di accedere a determinate directory.
Il punto di partenza è l’errore che si manifesta quando andiamo a lanciare mysqld (per comodità lavoro come root):

# service mysql start

Job for mysql.service failed because the control process exited with error code. See "systemctl status mysql.service" and "journalctl -xe" for details.

Qui occorre fare diagnosi come indicato nel messaggio d’errore:

# journalctl -xe
-- L'unità mysql.service ha iniziato la fase di avvio.
mag 08 10:37:50 jsbach audit[11686]: AVC apparmor="DENIED" operation="open" profile="/usr/sbin/mysqld" name="/proc/11686/status" pid=11686 comm="mysqld" requested_mask="r" denied_mask="r" fsuid=120 ouid=120
mag 08 10:37:50 jsbach audit[11686]: AVC apparmor="DENIED" operation="open" profile="/usr/sbin/mysqld" name="/sys/devices/system/node/" pid=11686 comm="mysqld" requested_mask="r" denied_mask="r" fsuid=120 o
mag 08 10:37:50 jsbach audit[11686]: AVC apparmor="DENIED" operation="open" profile="/usr/sbin/mysqld" name="/proc/11686/status" pid=11686 comm="mysqld" requested_mask="r" denied_mask="r" fsuid=120 ouid=120
mag 08 10:37:50 jsbach kernel: audit: type=1400 audit(1525768670.619:280): apparmor="DENIED" operation="open" profile="/usr/sbin/mysqld" name="/proc/11686/status" pid=11686 comm="mysqld" requested_mask="r" 
mag 08 10:37:50 jsbach kernel: audit: type=1400 audit(1525768670.619:281): apparmor="DENIED" operation="open" profile="/usr/sbin/mysqld" name="/sys/devices/system/node/" pid=11686 comm="mysqld" requested_ma
mag 08 10:37:50 jsbach kernel: audit: type=1400 audit(1525768670.619:282): apparmor="DENIED" operation="open" profile="/usr/sbin/mysqld" name="/proc/11686/status" pid=11686 comm="mysqld" requested_mask="r" 
mag 08 10:37:50 jsbach audit[11686]: AVC apparmor="DENIED" operation="mknod" profile="/usr/sbin/mysqld" name="/run/mysqld/mysqld.sock.lock" pid=11686 comm="mysqld" requested_mask="c" denied_mask="c" fsuid=1
mag 08 10:37:50 jsbach kernel: audit: type=1400 audit(1525768670.971:283): apparmor="DENIED" operation="mknod" profile="/usr/sbin/mysqld" name="/run/mysqld/mysqld.sock.lock" pid=11686 comm="mysqld" requeste
mag 08 10:37:52 jsbach systemd[1]: mysql.service: Main process exited, code=exited, status=1/FAILURE
mag 08 10:38:06 jsbach audit[11748]: AVC apparmor="STATUS" operation="profile_replace" profile="unconfined" name="/usr/sbin/mysqld" pid=11748 comm="apparmor_parser"
mag 08 10:38:06 jsbach kernel: audit: type=1400 audit(1525768686.555:284): apparmor="STATUS" operation="profile_replace" profile="unconfined" name="/usr/sbin/mysqld" pid=11748 comm="apparmor_parser"
mag 08 10:38:20 jsbach systemd[1]: Failed to start MySQL Community Server.

-- Subject: L'unità mysql.service è fallita

Ciò che occorre fare è informare apparmor perché non blocchi l’accesso alle directory indicate nel file di log: scorrendo la slide sopra ho evidenziato alcuni file che apparmor non permette a mysql di toccare; quindi si procede così:

# gedit /etc/apparmor.d/usr.sbin.mysqld

si aggiungono queste righe al file, stando attenti a scrivere all’interno dell parentesi graffe {}:

 /var/run/mysqld/mysqld.sock.lock rw,
 /run/mysqld/mysqld.sock.lock rw,
 /tmp/** rwk,
 /sys/devices/system/node/* r,
 /proc/* r,

Sia /sys/device che /proc/ hanno un asterisco perché il file che viene bloccato cambia ad ogni avvio.
Dopodiché si si fa un reload di apparmor.d:

# apparmor_parser -r /etc/apparmor.d/usr.sbin.mysqld

Ora si può riavviare mysqld:

# service mysql start
# mysql -u root -proot01
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.22-0ubuntu0.16.04.1 (Ubuntu)

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> ^DBye

E’ sparito PHP

Nel senso che Apache non attiva il modulo interprete di PHP.

Le pagine contenti PHP mi vengono servite così come sono, col codice e tutto, come se fossero un documento di testo o html.

In questo caso aggiungo il modulo mod_php5.6

# apt-get install libapache2-mod-php5.6

e lo attivo tramite /etc/apache2/mods-available/:

less /etc/apache2/mods-available/php5.6.load 
# Depends: mpm_prefork
LoadModule php5_module /usr/lib/apache2/modules/libphp5.6.so

È possibile anche installare e attivare il modulo PHP7, ma ovviamente occorre avviarne solo uno (quindi nei /mods-available/ si possono preparare varie versioni di PHP e poi creare il link ad uno solo di questi nella directory /mods-enabled/). Fatto questo si può verificare la correttezza della configurazione e finalmente avviare Apache:

# apache2ctl configtest 
Syntax OK
# service apache2 start
#

Due parole su AppArmor

Dal Wiki abbiamo la definizione pulita:

AppArmor è un’implementazione del «Linux Security Module» per il controllo degli accessi vincolante basato sul nome. AppArmor racchiude individualmente i programmi in un insieme di file e capacità posix 1003.1e draft.

È un sistema di sicurezza MAC (Mandatory Access Control) per Linux e serve per integrare ed estendere le politiche di sicurezza di Linux sui programmi in esecuzione ad un livello applicazione (quindi AppArmor fa la guardia al comporatmento delle applicazioni stando sopra al sistema operativo allo stesso loivello dell’applicazione da controllare).

Il controllo si effettua mediante creazione di profili, che sono dei file descrittivi che di solito vengono salvati nella directory

$ ll /etc/apparmor.d/
...
-rw-r--r-- 1 root root 8467 apr 4 13:58 usr.bin.firefox
-rw-r--r-- 1 root root 38551 dic 20 2016 usr.bin.webbrowser-app
-rw-r--r-- 1 root root 21143 apr 11 15:11 usr.lib.snapd.snap-confine.real
-rw-r--r-- 1 root root 8084 lug 27 2015 usr.lib.telepathy
-rw-r--r-- 1 root root 469 set 14 2015 usr.sbin.cups-browsed
-rw-r--r-- 1 root root 5119 ott 8 2015 usr.sbin.cupsd
-rw-r--r-- 1 root root 546 set 18 2015 usr.sbin.ippusbxd
-rw-r--r-- 1 root root 1264 mag 8 10:48 usr.sbin.mysqld
...

Nell’esempio sopra (mySql) apparmor.d bloccava l’accesso di mysqld a determinate directory al di là dell’accessibilità concessa dal sistema operativo.

Bibliografia

Ho trovato utili vari siti, tra cui:

Installare PHP 5.6 su Ubuntu 16.04

https://linuxconfig.org/how-to-upgrade-to-ubuntu-18-04-lts-bionic-beaver

Upgrade Ubuntu 16.04 LTS to Ubuntu 18.04 LTS Server

 

Pillole LaTeX: aggiungere un package

LaTeX è il sistema di redazione di documenti scientifici più popolare da ormai più di 20 anni.

Le potenzialità sono state ampliate nel tempo fornendo dei componenti terzi che sono agganciabili al motore di LaTeX eseguando l’installazione di un pacchetto (package)

Un esempio: il package Tikz-feynman, che aggiunge la possibilità di disegnare diagrammi di Feynman.

Istruzioni

  1. Scaricare il package (per esempio del sito dello sviluppatore Joshua Ellis)
  2. estrarre il pagkage (un tarball tar.gz) sotto il path di installazione di LaTeX: nel mio caso è
    /usr/share/texlive/texmf-dist/tex/latex
  3. aggiornare il database dei package del motore latex (necessario se abbiamo installato sotto /sr/bin… che è una installazione globale – cioè accessibile a tutti gli utenti della macchina
    $ sudo mktexlsr
    mktexlsr: Updating /usr/local/share/texmf/ls-R…
    mktexlsr: Updating /var/lib/texmf/ls-R-TEXLIVEDIST…
    mktexlsr: Updating /var/lib/texmf/ls-R-TEXMFMAIN…
    mktexlsr: Updating /var/lib/texmf/ls-R…
    mktexlsr: Done.
  4. Have fun:  nel preambolo sorgente LaTeX, includere il package:
    \usepackage{tikz}
    \usepackage[compat=1.1.0]{tikz-feynman}

Il programma

\feynmandiagram [horizontal=a to b] {
   i1 -- [fermion] a -- [fermion] i2,
   a -- [photon] b,
   f1 -- [fermion] b -- [fermion] f2,
};
produrrà questo diagramma di Feynman

Pillole Unix/Linux: il comando grep

grep (GNU Regular Expression Parser) è un utilissimo programma per analizzare testi. A cosa serve analizzare un testo? per esempio: trovare tutti i documenti di testo dentro ad un disco o ad una directory in cui compare la parola “mail”, quando non abbiamo la più pallida idea di dove sia. Qui in realtà occorre un concorso di programmi: uno che fa la scansione dell’albero di filesystem e, in pipe, quello che analizza il file correntemente puntato dal primo programma.

Ad esempio mi pongo in una certa directory e lancio il programma

$ find . -name "*php" -exec grep -H "mail" {} \;

Il programma che scansiona l’albero da quel punto “.” in giù, alla ricerca di tutti i file che finiscono per php è find.

Il programma che analizza ogni singolo file ritornato da find è grep.

Ma concertiamoci su grep. Molti di voi lo sapranno già, ma io me ne sono reso conto stamattina. Il programma grep ha delle limitazioni abbastanza forti.

Ad esempio, questo comando dovrebbe ritornare 012, e invece non ritorna nulla:

$ echo 012 | grep "[0-9]+"
$

Eppure l’espressione regolare recita “una o più cifre”.

Magicamente ho scoperto che invece il comando egrep (extended grep) fa il suo lavoro:

$ echo 012 | grep "[0-9]+"
012

Cercando in rete questa cosa viene citata come una limitazione di grep. È tutto.

 

 

Pillole di TCP/IP: l’utility PING

Ping è un programma disponibile in tutti i sistemi operativi che permette di controllare se un host o più in generale, una qualsiasi interfaccia di rete anche di un router, è raggiungibile dal punto in cui siamo.

Ping è una utility che invia e riceve messaggi ICMP (Internet Control Message Protocol). Partiamo da questo protocollo.

ICMP è un protocollo (in sostanza, come tutti i protocolli, un set di comandi per svolgere una determinata operazione) di supporto della più vasta suite IP (Internet Protocol). Con ICMP non si trasferiscono messaggi creati dall’utente ma solo informazioni sullo stato della rete, di solito elaborate dagli stessi dispositivi che se li scambiano.

ICMP è stato definito dallo IANA nel settembre del 1981 per opera di Jon Postel (il papà anche di FTP e di DNS). La RFC in cui è definito è la rfc792.

I messaggi ICMP vengono inviati in diverse situazioni: per esempio, quando un datagramma (un pacchetto) non riesce a raggiungere la sua destinazione; quando un gateway (uno “smistatore”) non ha la capacità di accumulazione (buffering) necessaria per reindirizzare un pacchetto o quando il gateway può forzare l’host a inoltrare il traffico su un percorso (route) più corto. [1]

Facciamo anche un piccolo approfondimento sulla suite TCP/IP completa.

ICMP usa la suite IP come se fosse un protocollo di grado superiore, come TCP o UDP, ma è progettato come tutti i protocolli IP per essere non assolutamente affidabile (not absolutely reliable), in quanto non viene fatto un controllo sulla correttezza della trasmissione. Quindi ICMP è a tutti gli effetti parte del protocollo IP.

Infatti, il protocollo IP non è stato progettato per essere assolutamente affidabile. Lo scopo di questi messaggi di controllo è di fornire un feedback sui problemi di comunicazione, non quella di rendere il protocollo IP affidabile. Non c’è nemmeno la garanzia che un pacchetto di controllo sarà effettivamente inoltrato oppure che sarà  effettivamente ricevuto. Qualche pacchetto può venire perso (e con PING molte volte si può vedere che capita) senza alcuna informazione di ritorno sulla loro perdita. Nel quadro del protocollo TCP/IP, sono gli stessi protocolli di ordine superiore costruiti sopra IP che devono implementare le loro specifiche procedure di controllo se è richiesta una comunicazione affidabile.

Questo per una visione generale nel quadro del procollo TCP/IP.

I messaggi ICMP sono quindi dei datagrammi incapsulati dentro a pacchetti IP e sono usati sia con i protocolli IPv4 che con IPv6. Questi pacchetti partono con una intestazione IP, seguita dall’intestazione ICMP, il tipo, il codice, il codice di controllo (checksum) e i dati da trasmettere che sono determinati univocamente dai campi tipo e codice che identificano il messaggio da inviare. [2]

I tipi di messaggi ICMP che vengono  inviati esplorativamente per saggiare lo stato della rete, informano l’host sul verificarsi di varie circostanze:

  • rete non raggiungibile o di host non raggiungibile (Destination Unreacheable Message),
  • gateway sovraccarico (source quence message)
  • echo
  • Time Exceeded

 

I messaggi ICMP sono trasmessi con un messaggio IP ordinario la cui intestazione è

  • Versione (4 o 6)
  • IHL (Internet Header Length) di 32 bit
  • Tipo di servizio: 0
  • Identificazione, flag, fragment offset
  • TTL (Time To Live in secondi): essendo questo campo decrementato di uno da ogni macchina attraversata dal datagramma, il suo valore dovrebbe essere maggiore o uguale al numero di gateway che il datagramma attraversa.
    In altre parole, ogni router che prende in consegna un messaggio ICMP, decrementa questo valore di 1 e il pacchetto viene preso in gestione finché questo numero è positivo. Quando esso si annulla, il pacchetto viene scartato e non più inoltrato. Questo ha a che vedere con gli hop necessari a inviare un messaggio ICMP (un messaggio IP in generale) dalla sorgente alla destinazione. I nodi che può attraversare sono molti e uno degli scopi di ICMP è quello di trovare un routing ottimale che minimizzi il numero di hop necessari.
  • Protocollo: ICMP = 1
  • Header Checksum: codice di controllo dell’header, nella prima versione della RFC è i complemento a 1 dei primi 16 bit dell’header
  • Indirizzo IP sorgente
  • Indirizzo IP destinazione

La parte dati del datagramma poi inizia con il tipo del messaggio ICMP; i messaggi ICMP hanno tutti questa forma:

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1  <-- 32 bit
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |     Type      |     Code      |          Checksum             |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                             unused                            |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      Internet Header + 64 bits of Original Data Datagram      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

I tipi di messaggio (network/destination unreacheable, echo, time exceeded, …) sono determinati dal Type e dal Code.

Noi siamo partiti dal comando PING che in sostanza è l’invio un messaggio ICMP di tipo echo, ma i messaggi ICMP sono ordinariamente inviati dai vari dispositivi per informarsi sullo stato della rete.

Nel caso del ping, come detto, implementiamo un messaggio echo o reply che è così costituito:

  • Type: 0 (se messaggio echo) oppure 8 (se messaggio reply)
  • Code: 0
  • Checksum
  • Identificatore
  • Numero di sequenza, che è l’icmp_seq che leggiamo nel ping:
$ ping www.google.com
PING www.google.com (172.217.21.68) 56(84) bytes of data.
64 bytes from mrs08s05-in-f4.1e100.net (172.217.21.68): icmp_seq=1 ttl=49 time=78.1 ms
64 bytes from mrs08s05-in-f4.1e100.net (172.217.21.68): icmp_seq=2 ttl=49 time=64.4 ms
64 bytes from mrs08s05-in-f4.1e100.net (172.217.21.68): icmp_seq=3 ttl=49 time=60.9 ms
^C
--- www.google.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 60.902/67.815/78.141/7.440 ms

Come funziona il datagramma ICMP di tipo echo/reply

I dati ricevuti dal messaggio di echo devono essere ritornati nel messaggio echo di risposta (reply).
L’identificatore e il numero di sequenza posso essere usati dal mittente il messaggio di echo per agevolare il confronto delle risposte con le richieste di echo.
Per esempio l’identificatore può essere usato come una porta TCP/UDP per identificare una sessione, e il numero di sequenza può essere incrementato da ogni invio di una richiesta echo. Il destinatario (echoer) ritornerà questi stessi valori nella risposta all’echo.

Quindi nell’output del messaggio ping vediamo il TTL, la sequenza del pacchetto e il round trip time (tempo di andata e ritorno tra un messaggio di echo e uno di reply).

Un’altra cosa importante nei messaggi ICMP è che non vengono creati messaggi ICMP per inoltrare messaggi ICMP (controllo lo stato della rete per mandare un messaggio di controllo di stato della rete) perché questo porterebbe presto al blocco dei dispositivi. A questo proposito, un ultimo aspetto importante da considerare è che spesso il comando ping non è determinante nel caratterizzare la raggiungibilità di un host. Infatti posso fare in modo che un certo host rigetti i comandi di echo per evitare di impegnare risorse a inoltrare un comando reply. Infatti ping spesso viene usato come attacco dDOS.

Quindi potremmo avere un web server perfettamente rispondente anche se non è reattivo al ping.

 

Bibliografia

[1] http://www.ietf.org/rfc/rfc792.txt

[2] https://www.pcwdld.com/what-is-icmp-and-port

Image: Piaxabay Creative Commons CC0

Pillole di Unix/Linux: i servizi, i runlevel e gli script rc.d

Un servizio è un programma, o un insieme di programmi, che gira in background e di cui non ci preoccupiamo fino al momento in cui ne abbiamo bisogno. Esempi di servizi sono Apache, MySQL e CUPS (il server per la gestione delle stampanti). Un servizio è detto a volte service e a volte server.

Un runlevel è una fase di funzionamento del sistema operativo inteso come insieme di servizi che vengono accesi quando si entra in una determinata fase dall’avvio.

Il sistema operativo parte sempre dal runlevel 1 (livello in cui è consentito un accesso ad un singolo utente), progressivamente attraverso i livelli 2, 3, 4 e 5, livello al quale possiamo cominciare a lavorare con tutti i servizi funzionanti, compresa la GUI (Graphics User Interface) cioè l’interfaccia grafica a cui siamo abituati da molto tempo. Il tutto si esaurisce nel tempo che intercorre tra l’accensione del computer e la comparsa della maschera di login, quindi generalmente – se la macchina ha subito una corretta manutenzione – alcuni secondi.

Esistono due ulteriori livelli:

  • il livello 0 nel quale il sistema operativo entra per eseguire un arresto (HALT)
  • il livello 6 nel quale il sistema operativo entra per eseguire un riavvio (REBOOT)

Varie versioni di Unix hanno storicamente sviluppato diverse versioni dei runlevels:

  • BSD (Berkeley Software Distribution) per esempio i runlevel non ha li ha proprio 🙂
  • System V (AT & T) ha i runlevel seguenti, ognuno dei quali prevede avvio di specifici servizi: ad esempio il 2 è un funzionamento multi utente senza la rete, il 3 è un funzionamento multiutente con la rete ma solo in modalità testo, …, il 5 funzionamento multi utente con rete e interfaccia grafica).
  • Debian (da cui deriva Ubuntu) hai il runlevel 1 single user text mode, e 3, 4 e 5 multi user completo.

L’ordine di avvio dei runlevel viene impartito al sistema operativo dal file /etc/inittab.

Per le versioni derivate da Debian (come Ubuntu) invece il file /etc/inittab non esiste e l’ordine viene invece scritto dentro ai file contenuti nelle directory rcX.d, dove X = 0, …, 6

Ci si può spostare di runlevel all’occorrenza, ad esempio se si verificano errori strani o ci sono servizi che non partono. Basta scrivere da terminale (occorrono i privilegi di root)

# init [runlevel]

Se runlevel è eguale a 0 o 6, rispettivamente arrestiamo o riavviamo  la macchina.

Scrivendo il comando init 4, ad esempio, il sistema carica ed esegue gli script contenuti nella directory /etc/rc4.d/

Attenzione: ci sono situazioni nelle quali non è possibile aprire una shell e digitare il comando init . Questo accade ad esempio se proprio X (il server grafico) si è inchiodato (non risponde il mouse, non rispondono le finestre). Niente paura, questo non è Windows: possiamo entrare in una shell a runlevel 4 (solo testo) con la combinazione di tasti Ctrl+Alt+F6 o F7… ognuna delle quali combinazioni aprirà una shell di testo a schermo intero (in runlevel 4, il sistema è in modalità multi utente) dal quale si potrà agire sul servizio che non risponde (in questo caso ad esempio si può operare un riavvio di X). Ad esempio potremmo identificare l’id del processo X e killarlo. A quel punto X ripartirà automaticamente.

init è il padre di tutti i processi, il programma che lancia il sistema operativo. È senza dubbio il programma più importante del sistema operativo. Possiamo vedere ciò in quanto il suo PID (Process ID) è sempre il numero 1:

$ ps aux 
USER PID %CPU %MEM    VSZ  RSS TTY STAT  START TIME COMMAND
root 1    0.0  0.0 185152 5816   ?   Ss  11:29 0:01 /sbin/init splash
root 2    0.0  0.0      0    0   ?    S  11:29 0:00 [kthreadd]
root 3    0.0  0.0      0    0   ?    S  11:29 0:00 [ksoftirqd/0]
root 5    0.0  0.0      0    0   ?    S< 11:29 0:00 [kworker/0:0H]
root 7    0.1  0.0      0    0   ?    S  11:29 0:13 [rcu_sched]
root 8    0.0  0.0      0    0   ?    S  11:29 0:00 [rcu_bh]
...

 

Bibliografia

[1] http://www.linux.com

[2] Stephen Coffin, UNIX System V Release 4, 1990 McGraw-Hill

La codifica base64

Questa codifica permette di rappresentare file binari (o anche file di testo) in un formato che usa una base di soli 64 caratteri scelti tra i 128 caratteri dell’ASCII standard 7 bit: quale insieme? dipende dalla particolare implementazione, ma fondamentalmente sono

  • i 26 caratteri Maisuscoli [A-Z], seguiti
  • dai 26 caratteri minuscoli [a-z], seguiti
  • dalle 10 cifre [0-9] e
  • dai segni + [più] e / [slash]

È una tabella composta quindi di 26+26+10+2 = 64 caratteri.

A cosa è dovuto questo che potrebbe sembrare un arzigogolo inutile?

La posta elettronica si basa su questa codifica, per esempio: gli allegati alla mail, quale che sia il loro tipo MIME (sia esso un pdf, un breve video o un audio), vengono convertiti in TESTO puro.

Perché la trasmissione di mail è su base TESTUALE, si trasmette testo. Così anche HTTP: Hyper TEXT Transfer Protocol. Le immagini e i file multimediali in genere che viaggiano su HTTP vengono precedentemente convertite in TESTO.

Lo schema di codifica è il seguente: supponiamo di dover trasmettere con un protocollo di testo (SMTP o HTTP) la stringa “CIAO”.

Prendiamo per ciascun carattere la corrispondente codifica ASCII in binario e ne raggruppiamo le cifre 6 a 6:


Algoritmo per la determinazione dei caratteri base64

Quindi 0 viene mappato in A, 1 in B e così via, fino 61 che viene mappato sul carattere 9, più 62 mappato in + e 63 in /

L’algoritmo prevede che il numero di bit debba essere multiplo di 6, per cui eventualmente si opera un padding (i 4 zeri verdi nel nostro caso); inoltre il numero di caratteri dev’essere multiplo di 4 per cui u questo caso si aggiungono da 0 a due caratteri =.

Varie implementazioni ritornano valori finali leggermente diversi: ad esempio, per evitare problemi inserendo una stringa base64 nell’URL, è necessario evitare il carattere /.

Nella mia implementazione Ubuntu:

$ base64 --version
base64 (GNU coreutils) 8.23
Copyright © 2014 Free Software Foundation, Inc.
Licenza GPLv3+: GNU GPL versione 3 o successive <http://gnu.org/licenses/gpl.html>
Questo è software libero: è possibile modificarlo e ridistribuirlo.
Non c'è ALCUNA GARANZIA, nei limiti permessi dalla legge.

Scritto da Simon Josefsson.

il risultato è

$ echo CIAO | base64
Q0lBTwo=

il padding, in questa implementazione, viene fatto con o=.

Per una immagine il procedimento è lo stesso: si prendono i bytes, si raggruppano per 6, si converte nei caratteri della tabella A-Za-z0-9+/ più eventuale padding

  • di zeri per arrivare ad un numero di bit multiplo di 6 e
  • di caratteri per arrivare ad un numero di caratteri multiplo di 4.