Page suivante - Page précédente - Table des matières

3. Virtuald

3.1 Comment ça marche

Toute connexion réseau est composée de deux paires adresse IP/port. L'API (Applications Program Interface, ou Interface de Programmation d'Applications) pour la programmation réseau est nommée l'API Sockets. La socket agit comme un fichier ouvert, et vous pouvez envoyer ou recevoir des données à travers une connexion réseau en lisant ou en écrivant dans la socket. Il existe une fonction, getsockname, qui retourne l'adresse IP de la socket locale. Virtuald utilise getsockname pour déterminer sur quel adresse IP de la machine locale la connexion a été faite. Virtuald lit un fichier de configuration pour récupérer le répertoire associé à cette adresse IP. Il va utiliser chroot sur ce répertoire et prendre en compte la connexion au service. Chroot change le répertoire / (le répertoire root) vers un nouveau point, de sorte que tout ce qui est au dessus de ce répertoire devienne inaccessible pour le programme. Ainsi, chaque adresse IP se voit assigné un système virtuel de fichiers. Pour le programme réseau, ceci est transparent, et le programme va se comporter comme si de rien n'était. Virtuald, en conjonction avec un programme comme inetd, peut être utilisé pour virtualiser n'importe quel service.

3.2 inetd

Inetd est un super serveur réseau qui écoute sur de multiples ports et, lorsqu'il reçoit une demande de connexion (par exemple, une requête POP), inetd réalise la connexion et l'envoie au programme spécifié. Cela évite de faire tourner des serveurs pour rien lorsqu'il n'y a aucune demande pour eux

Un fichier /etc/inetd.conf standard ressemble à ceci :

ftp stream tcp nowait root /usr/sbin/tcpd \
 wu.ftpd -l -a
pop-3 stream tcp nowait root /usr/sbin/tcpd \
 in.qpop -s

Un fichier /etc/inetd.conf virtualisé ressemble à ceci :

ftp stream tcp nowait root /usr/bin/virtuald virtuald /virtual/conf.ftp wu.ftpd -l -a
pop-3 stream tcp nowait root /usr/bin/virtuald virtuald /virtual/conf.pop in.qpop -s

3.3 Fichier de Configuration

Chaque service se voit attribué un fichier de configuration qui contrôlera quelles IPs et quels répertoires sont autorisés pour ce service. Vous pouvez avoir un fichier de configuration principal ou de nombreux fichiers de configuration si vous désirez que chaque service se voit attribuer une liste de domaines différents. Un fichier de configuration ressemble à ceci :

# C'est un commentaire, comme le sont les lignes blanches
# Format IP "ESPACE" dir "PAS D'ESPACES"
10.10.10.129 /virtual/foo.bar.com
10.10.10.130 /virtual/bar.foo.com
10.10.10.157 /virtual/boo.la.com

3.4 Le code source de virtuald

Ceci est un code source en C du programme virtuald. Compilez-le et installez-le dans /usr/local/bin avec les permissions 0755, l'utilisateur root, et le groupe root. La seule option de compilation est VERBOSELOG qui active ou désactive l'option de log.

#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include <syslog.h>
#include <stdio.h>
#define BUFSIZE 8192
int getipaddr(char **ipaddr)
{
 struct sockaddr_in virtual_addr;
 static char ipaddrbuf[BUFSIZE];
 int virtual_len;
 char *ipptr;
 virtual_len=sizeof(virtual_addr);
 if (getsockname(0,(struct sockaddr *)&virtual_addr,&virtual_len)        {
 syslog(LOG_ERR,"getipaddr: getsockname failed: %m");
 return -1;
 }
 if (!(ipptr=inet_ntoa(virtual_addr.sin_addr)))
 {
 syslog(LOG_ERR,"getipaddr: inet_ntoa failed: %m");
 return -1;
 }
 strncpy(ipaddrbuf,ipptr,sizeof(ipaddrbuf)-1);
 *ipaddr=ipaddrbuf;
 return 0;
}
int iptodir(char **dir,char *ipaddr,char *filename)
{
 char buffer[BUFSIZE],*bufptr;
 static char dirbuf[BUFSIZE];
 FILE *fp;
 if (!(fp=fopen(filename,"r")))
 {
 syslog(LOG_ERR,"iptodir: fopen failed: %m");
 return -1;
 }
 *dir=NULL;
 while(fgets(buffer,BUFSIZE,fp))
 {
 buffer[strlen(buffer)-1]=0;
 if (*buffer=='#' || *buffer==0)
 continue;
 if (!(bufptr=strchr(buffer,' ')))
 {
 syslog(LOG_ERR,"iptodir: strchr failed");
 return -1;
 }
 *bufptr++=0;
 if (!strcmp(buffer,ipaddr))
 {
 strncpy(dirbuf,bufptr,sizeof(dirbuf)-1);
 *dir=dirbuf;
 break;
 }
 if (!strcmp(buffer,"default"))
 {
 strncpy(dirbuf,bufptr,sizeof(dirbuf)-1);
 *dir=dirbuf;
 break;
 }
 }
 if (fclose(fp)==EOF)
 {
 syslog(LOG_ERR,"iptodir: fclose failed: %m");
 return -1;
 }
 if (!*dir)
 {
 syslog(LOG_ERR,"iptodir: ip not found in conf file");
 return -1;
 }
 return 0;
}
int main(int argc,char **argv)
{
 char *ipaddr,*dir;
 openlog("virtuald",LOG_PID,LOG_DAEMON);
#ifdef VERBOSELOG
 syslog(LOG_ERR,"Virtuald Starting: $Revision: 1.1.1.1 $");
#endif
 if (!argv[1])
 {
 syslog(LOG_ERR,"invalid arguments: no conf file");
 exit(0);
 }
 if (!argv[2])
 {
 syslog(LOG_ERR,"invalid arguments: no program to run");
 exit(0);
 }
 if (getipaddr(&ipaddr))
 {
 syslog(LOG_ERR,"getipaddr failed");
 exit(0);
 }
#ifdef VERBOSELOG
 syslog(LOG_ERR,"Incoming ip: %s",ipaddr);
#endif
 if (iptodir(&dir,ipaddr,argv[1]))
 {
 syslog(LOG_ERR,"iptodir failed");
 exit(0);
 }
 if (chroot(dir)<0)
 {
 syslog(LOG_ERR,"chroot failed: %m");
 exit(0);
 }
#ifdef VERBOSELOG
 syslog(LOG_ERR,"Chroot dir: %s",dir);
#endif
 if (chdir("/")<0)
 {
 syslog(LOG_ERR,"chdir failed: %m");
 exit(0);
 }
 if (execvp(argv[2],argv+2)<0)
 {
 syslog(LOG_ERR,"execvp failed: %m");
 exit(0);
 }
 closelog();
 exit(0);
}


Page suivante - Page précédente - Table des matières