DNS dinamico fai-da-te senza servizi di terze parti (UPDATE: 30/04/2020)

Rimpiazzare il proprio servizio di DNS dinamico con una coppia di script PHP e bash.

Esistono moltissimi servizi online anche gratuiti per il DNS dinamico quali DynDNS o NoIP. Questi servizi permettono l’associazione del propro indirizzo IP dinamico ad un nome DNS statico. Grazie ad essi è possibile raggiungere i servizi web installati dietro le proprie ADSL casalinghe (opportunamente nattate) senza dover ricordare e prendere nota dell’indirizzo IP pubblico che il provider di volta in volta ci fornisce.

Avevo un account su DynDNS per gestire da remoto il mio disco di backup ReadyNAS ma purtroppo dopo molto tempo il servizio è stato revocato e messo a pagamento. A tal punto, avendo già un dominio web PHP+MySQL (questo blog per l’appunto) ho deciso di implementarvi sopra un semplice servizio di traduzione IP in modo da raggiungere di nuovo il disco di backup.

Si è trattato semplicemente di realizzare una pagina web PHP che fornisce un redirect automatico (redirect HTML) al proprio indirizzo IP pubblico. L’indirizzo IP pubblico è memorizzato online in un file di testo ip.txt. E’ chiaro che tale indirizzo cambia con regolarità (al termine del lease-time impostato dal provider o ad ogni riavvio del modem ADSL) e quindi deve esistere un meccanismo per aggiornare tale file con il nuovo indirizzo. Un piccolo script bash che gira localmente sul ReadyNAS provvede ad aggiornare periodicamente il file remoto tramite una semplice richiesta HTTP GET.

In sostanza si tratta di realizzare due software distinti:

  1. ipremote.php: pagina PHP remota sul proprio dominio web che effettua il redirect all’indirizzo IP di casa
  2. ipupdater.sh: script bash locale (dietro ADSL) che ad intervalli regolari notifica la pagina web inviando il nuovo indirizzo IP

1) Pagina PHP (ipremote.php)

Molto semplicemente assolve alla duplice funzione di 1) redirect automatico e 2) aggiornamento del file ip.txt da parte dello script bash locale. Per accedere come redirect basta fornire la password corretta (in questo caso 123456) tramite una semplice richiesta GET: la pagina legge l’indirizzo IP pubblico corrente dal file e crea l’HTML per il redirect a quell’indirizzo. Per accedere in modalità aggiornamento (script bash presumibilmente) basta fornire, sempre in GET,  la password: la pagina salverà l’indirizzo IP nel file di testo.

Ecco il codice:


<?php

$file = "ip.txt";

function get_client_ip() {
    $ipaddress = '';
    if (getenv('HTTP_CLIENT_IP'))
        $ipaddress = getenv('HTTP_CLIENT_IP');
    else if(getenv('HTTP_X_FORWARDED_FOR'))
        $ipaddress = getenv('HTTP_X_FORWARDED_FOR');
    else if(getenv('HTTP_X_FORWARDED'))
        $ipaddress = getenv('HTTP_X_FORWARDED');
    else if(getenv('HTTP_FORWARDED_FOR'))
        $ipaddress = getenv('HTTP_FORWARDED_FOR');
    else if(getenv('HTTP_FORWARDED'))
       $ipaddress = getenv('HTTP_FORWARDED');
    else if(getenv('REMOTE_ADDR'))
        $ipaddress = getenv('REMOTE_ADDR');
    else
        $ipaddress = 'UNKNOWN';
    return $ipaddress;
}
if(isset($_GET['newip']) == true && isset($_GET['pass']) == true)
{
   $ip = get_client_ip();
   $pass = $_GET['pass'];

   if($pass == "123456")
   {
      // update IP address
      file_put_contents($file, $ip);
   }
   else
   {
      echo "wrong password";
   }
}
else if(isset($_GET['pass']) == true)
{
   $pass = $_GET['pass'];

   if($pass == "123456")
   {
      // get IP address
      $ip = file_get_contents($file);
      // redirect
      header('Location: http://'.$ip);
      die();
   }
   else
   {
      echo "wrong password";
   }
}

?>

2) Script bash locale (ipupdater.sh)

Lo script bash viene eseguito periodicamente grazie a cron (ebbene si, il ReadyNAS è un embedded Linux a tutti gli effetti) e provvede a rilevare l’indirizzo pubblico corrente e a notificarlo alla pagina web PHP remota. La regola cron può essere impostata ad una frequenza di una volta al minuto, una volta all’ora o quello che si vuole: più il rate di notifica è alto più bassa sarà la probabilità di trovare la pagina web momentaneamente disallineata con il vero indirizzo IP.

Ecco lo script:

#!/bin/bash
password="123456"
url="http://www.mysite.it/ipremote.php?newip=&pass=$password"
wget -qO- $url &> /dev/null

Lo script si limita a comporre la stringa URL con la richiesta GET di aggiornamento IP verso la pagina ipremote.php. www.mysite.it è il proprio dominio web, dove risiede ipremote.php.
Viene poi inoltrata la richiesta HTTP GET tramite comando wget.

Come si usa

Accedere al ReadyNAS locale diventa ora banale: basta collegarsi all’indirizzo http://www.mysite.it/ipremote.php?pass=123456 per ottenere il redirect.
Ovvimente il sistema funziona non solo per accedere a dischi di rete, ma tutto quello che avete deciso di esporre nella vostra rete LAN (pannello di gestione remota del modem ADSL, VNC server, programmi vari etc..).

Perchè la password?

E’ chiaro che solo lo script bash locale deve essere in grado di aggiornare l’indirizzo altrimenti potreste ritrovarvi con un redirect ad un IP impostato da terzi. Anche il semplice redirect deve essere protetto da password, più che altro per questioni di privacy: conviene che solo voi possiate raggiungere i servizi della vostra rete LAN (protetti anch’essi da password, ovviamente).

Conclusioni

Vantaggi del sistema? Innanzitutto non occorre registrarsi e fare affidamento a servizi di terze parti (DynDNS, NoIP etc..). Il sistema non soffre dei ritardi di propagazione tipici del DNS per cui il nuovo IP pubblico è prontamente rilevato e aggiornato (basta settare un rate di aggiornamento ragionevolmente breve, tipo 5 minuti). Con un pò di fortuna è possibile embeddare lo script bash direttamente nel modem ADSL; è sufficiente che il modem si appoggi su una qualche distro Linux e abbia il demone cron installato.

Esistono alcuni svantaggi però: la password fissa è soggetta ad attacchi di tipo replay-attack. Converrebbe implementare o un rolling code (ma introduce la possibilità di disallineamento) o meglio ancora uno schema più raffinato di tipo challenge-response.
Altro problema:  occorre avere un dominio web PHP funzionante dove appoggiare la pagina ipremote.php. Ma ne esistono molti gratuiti come ad esempio l’ottimo Altervista

61
Leave a Reply

avatar
23 Comment threads
38 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
23 Comment authors
zalexLivioGianlucaStefanoSandro Recent comment authors
zalex
zalex

Salve, ho fatto tutto e messo su raspberry p3b e funziona il redirect. Io però avrei bisogno se è possible di avere il redirect a una porta del router e se metto ad esempio http://www.mysite.it/ipremote.php?pass=123456:num porta , ovviamente mi dice password errata. Se faccio da browser risolvo mettendo il numero porta nella barra indirizzo dove rimane l’IP del mio router, ma se lo faccio da app accesso remoto nasce il problema.Si puo risolvere, grazie

Livio
Livio

Grazie Gianluca per questo articolo. E’ proprio quello che mi serviva.
Conosci SinRic.com? Sto facendo delle prove per interfacciare una scheda similArduino con Alexa, ma non mi piace molto l’idea di appoggiarmi ad entità esterne.
Avendo a disposizione un sito web pensi che si possa implementare qualcosa di simile a SinRic?
Grazie
Livio

Stefano
Stefano

Posso dire bravo. Complimenti lo script funziona alla grande sia lato server sia lato client su RaspBerry PI che uso come stazione meteo. Ho cambiato solo la variabile $pass perchè su alcuni sistemi con installati alcuni script php per evitare gli attacchi brute force, la parola “pass” gli dava fastidio.
Poi per semplicità anzichè creare uno script bash da chiamare poi nel crontab ho messo tutta la chiamata direttamente li.
Meno elegante, ma più rapido.
Ancora complimenti e grazie.

Sandro
Sandro

Grazie per l’esempio, funziona ottimamente.
Però ho dovuto aggiungere &newip nella riga 3 dello script .sh
url=”http://www.mysite.it/ipremote.php?pass=$password&newip”

roberto
roberto

Ciao Gianluca, ho trovato interessante il tuo articolo ma mi chiedo perchè non utilizzare $_SERVER[‘REMOTE_ADDR’] per avere direttamente l’indirizzo del client (che in questo caso è il tuo NAS) ?

Gianluca
Gianluca

Ciao Roberto, pechè quando ho scritto l’articolo non sapevo della variabile $_SERVER[‘REMOTE_ADDR’]!!!! 🙂

Con REMOTE_ADDR il sistema si semplifica enormemente, non serve nemmeno più il servizio whatsmyip per conoscere il proprio indirizzo IP da inviare al server. Inoltre è più sicuro, è più complicato spoofare un indirizzo IP diverso dal proprio. Ti andrebbe di scrivere un nuovo articolo sul mio blog con il nuovo sistema? Posso darti l’accesso in scrittura al nuovo articolo. Ciao fammi sapere e grazie

Hella
Hella

Ciao Gianluca, volevo sapere se avessi provveduto ad aggiornare la guida oppure no.