[Linux-Biella] dns dinamico howto [lungo] - frutto di un weekend piovoso...

leonardo LeOS buffa leos a bilug.linux.it
Lun 12 Set 2005 14:46:13 CEST


immaginate di avere ip dinamico ma di sapere sempre il vostro ip
esistono infatti provider che offrono questo tipo di servizio, dyndns,
no-ip, etc, ma a voi stanno sulle palle per vari motivi...

ecco la soluzione, che comunque prevede un minimo di preparazione
riguardo socket, dns, firewall, quindi prima di tutto un buon sano rtfm
:D


require:
- un vostro dominio
- il server su cui gira il dns autoritativo per il vostro dominio

software:
knockd (http://www.zeroflux.org/cgi-bin/cvstrac/knock/wiki)
updatedns (allegato updatedns.c)
ipfw (allegato ipfw shell script)
mailer.pl (allegato programmillo in perl)

sul server dns installate il knockd e configuratelo come segue:
[options]
        logfile = /var/log/knockd.log

[ipfw]
        sequence    = X,Y,Z
        seq_timeout = 5
        command     = /opt/bin/ipfw %IP%
        tcpflags    = syn


quando dalla rete con IP dinamico bussate (knock IPserver X Y Z) questo
esegue il comando /opt/bin/ipfw passandogli come parametro il vostro IP
(%IP%)

il programmillo ipfw interroghera' il dns per vedere il vecchio ip
assegnato e se questo e' cambiato lancia il programma updatedns per
aggiornare il file del dominio, cambiando l'ip della entry e aggiornando
il seriale (troppo sbattimento a calcolarlo correttamente AAAAMMGGXX 
quindi semplicemente aggiunge 1)

(se i vostri fairuols avranno come namserver quello autoritativo per il
vostro dominio, in tempo reale saranno in grado di riconoscervi come
fw.dominio.tld, altrimenti ricordatevi di mettere il ttl al minimo di
modo che gli aggiornamenti vengano propagati in fretta, altri dns
permettendo...)

mailer.pl si occupera' di mandare email ed eventualmente sms comunicando
il nuovo IP

ed ecco quindi a voi tutti il codice utilizzato per tale simpatica e
socialmente utile iniziativa:

--- ipfw ---
#!/bin/bash

oldip=`host fw.pfctl.net|awk {'print $4'}`
newip=$1
dnsfile="/var/named/pfctlnet.hosts"
dnsentry="fw"

date >> /var/log/ipfw.log
echo $newip >> /var/log/ipfw.log

if [ "$newip" != "$oldip" ] ; then
  echo "ip changes!!!" >> /var/log/ipfw.log
  # manda la mail
  /opt/bin/mailer.pl $newip

  # aggiorna il dns
  /opt/bin/updatedns $newip $dnsfile $dnsentry
  /bin/killall -HUP named
else
  echo "no changes" >> /var/log/ipfw.log
fi



--- mailer.pl ---
#!/usr/bin/perl

use Socket;
use strict; 

my($newip)=$ARGV[0];
my($mailserver)="127.0.0.1";
my($mailfrom)='email\@dominio.tld';
my(@mailto)=('destinatario\@dominio.tld','+39numerovodafone\@sms.vodafo
ne.it');

my($realName) = "SMS alert";
my($subject) = "IP Changed: $newip";
my $data = localtime time;

my($proto) = 6;
my($port) = 25;

socket(SMTP, AF_INET(), SOCK_STREAM(), $proto)
or die("socket: $!");

connect(SMTP, sockaddr_in($port, inet_aton($mailserver)))
or die("connect: $!");

select(SMTP); $| = 1; select(STDOUT);
{
  my($inpBuf) = '';
  recv(SMTP, $inpBuf, 200, 0);
}

sendSMTP(1, "HELO alert.intra\r\n");
sendSMTP(1, "MAIL From: <$mailfrom>\r\n");

foreach (@mailto) {
  sendSMTP(1, "RCPT To: <$_>\r\n");
}

sendSMTP(1, "DATA\r\n");
send(SMTP, "Date: $data \r\n",0);
send(SMTP, "From: $realName\r\n", 0);
send(SMTP, "Subject: $subject\r\n", 0);
sendSMTP(1, "\r\n.\r\n");
sendSMTP(1, "QUIT\r\n");

close(SMTP);

sub closeSocket {
  close(SMTP);
  die("SMTP socket closed due to SIGINT\n");
} 

sub sendSMTP {
  my($debug, $buffer) = @_;
  send(SMTP, $buffer, 0);
  recv(SMTP, $buffer, 200, 0);
  return( (split(/ /, $buffer))[0] );
}


--- updatedns.c ---
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BL 1024

/*scopre se la linea contiene la parola serial*/
int find_serial(char *buf) {
  unsigned int i;

  for (i=0;i<strlen(buf);i++)
    if (strncmp (buf+i,"serial",6)==0)
      return 1;
  return 0;
}

/*prende il serial numer*/
long get_serial(char *buf) {
  unsigned int i;
  long ret;
  for (i=0;i<strlen(buf);i++)
  {	
    if (isdigit(buf[i])) {
      sscanf(buf+i,"%ld",&ret);
      return ret;
    }
  }
  return 0;
}


/*banalissimo, controlla che le prime lettere siano quelle
richieste della linea da aggiornare*/
int find_line(char *buf,char *pattern) {
  if (strncmp (buf,pattern,strlen(pattern))==0)
      return 1;
  return 0;
}

/*ritorna l'ip sotto forma di stringa, xche' son pigro*/
char *get_ip(char *buf) {
  unsigned int i;
  for (i=0;i<strlen(buf);i++)
  {	
    if (buf[i]=='A')
      return buf+i+2;
  }
}


/*
*
*sintassi <prog> <ip> <nomefile> <entry>
*
*/

int main (int argc, char *argv[])
{

  FILE *dnsfile;
  FILE *out;
  long serial;
  char *ip;

  if (argc != 4) {
    printf("sintassi %s <ip> <nomefile> <entry>\n",argv[0]);
    exit(-1);
  }

  /*apriamo in modalita' read*/
  dnsfile = fopen(argv[2],"r");

  while(!feof(dnsfile)) {
    char buf[BL];

    memset(buf,0,BL);
    fgets(buf,BL,dnsfile);

    if ((find_serial(buf)))	
      serial=get_serial(buf);

    else if ((find_line(buf,argv[3]))) 
      ip = strdup(get_ip(buf));
  }

/*a questo punto della nostra vita abbiamo un
bellissimo valore serial = serial number
e uno sfizioso valore ip, altrettanto bello
e gioioso*/

  /*il primo controllo, detto controllo
  dell'amicizia sovrana e dell'amore cosmico*/
  if (strncmp (ip,argv[1],strlen(argv[1]))==0)
    exit(0);

  /*ricominciamo*/
  rewind(dnsfile);

  out= fopen("out.tmp","w+");

  while (!feof(dnsfile)) {
    char buf[BL];
    memset(buf,0,BL);
    fgets(buf,BL,dnsfile);
    if ((find_serial(buf)))	
      fprintf(out,"                                %ld	;
serial\n",serial+1);    else if ((find_line(buf,argv[3])))
      fprintf(out,"%s\t\tIN\tA\t%s\n",argv[3],argv[1]);
    else
      fputs(buf,out);			
  }

  rewind(out);
  fclose(dnsfile);

  /*rename del file, barbonescamente*/
  /*apriamo in modalita' write*/
  dnsfile = fopen(argv[2],"w+");

  while (!feof(out)) {
    char buf[BL];
    memset(buf,0,BL);
    fgets(buf,BL,out);
    fputs(buf,dnsfile);
  }

  fclose(out);
  unlink("out.tmp");
  fclose(dnsfile);
  exit(0);
}



-- 

Just because you're paranoid doesn't mean they're not out to get you. 

Abbie Hoffman

main(){int n=-1;char c[]="qiruAbhjrc)fbfln#]g";
while(c[n]!='g'){putchar(c[++n]-'\05'+n);}return 0;}


Linux Registered User #135079

public gpg key: gpg --keyserver pgp.mit.edu --recv-key 5811D15E


Maggiori informazioni sulla lista Linux