Sophie

Sophie

distrib > Mandriva > 2010.1 > x86_64 > by-pkgid > 965e33040dd61030a94f0eb89877aee8 > files > 6803

howto-html-en-20080722-2mdv2010.1.noarch.rpm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD>
 <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
 <TITLE>Virtual Services Howto: Virtuald </TITLE>
 <LINK HREF="Virtual-Services-HOWTO-4.html" REL=next>
 <LINK HREF="Virtual-Services-HOWTO-2.html" REL=previous>
 <LINK HREF="Virtual-Services-HOWTO.html#toc3" REL=contents>
</HEAD>
<BODY>
<A HREF="Virtual-Services-HOWTO-4.html">Next</A>
<A HREF="Virtual-Services-HOWTO-2.html">Previous</A>
<A HREF="Virtual-Services-HOWTO.html#toc3">Contents</A>
<HR>
<H2><A NAME="s3">3. Virtuald </A></H2>

<H2><A NAME="ss3.1">3.1 Introduction</A>
</H2>

<P>Every network connection is made up of two IP address/port pairs.  
The API (Applications Program Interface) for network programming is 
called the Sockets API.  The socket acts like an open file and by 
reading/writing to it you can send data over a network connection.  
There is a function call <CODE> getsockname </CODE> that will return the 
IP address of the local socket.  Virtuald uses <CODE> getsockname </CODE>       
to determine which IP on the local machine is being accessed.  Virtuald reads 
a config file to retrieve the directory associated with that IP.  It will 
<CODE> chroot </CODE> to that directory and hand the 
connection off to the service.  <CODE> Chroot </CODE> resets / or the root 
directory to a new point so everything higher in the directory tree is cut 
off from the running program.   Therefore, each IP address gets their own 
virtual filesystem.   To the network program this is transparent 
and the program will behave like nothing happened.  Virtuald
in conjunction with a program like inetd can then be used to 
virtualize any service.
<P>
<H2><A NAME="ss3.2">3.2 Inetd </A>
</H2>

<P>Inetd is a network super server that listens at multiple ports 
and when it receives a connection (for example, an incoming pop 
request), inetd performs the network negotiation and hands the 
network connection off to the specified program.  This prevents 
services from running idly when they are not needed.  
<P>
<P>A standard /etc/inetd.conf file looks like this:
<P>
<PRE>
ftp stream tcp nowait root /usr/sbin/tcpd \
        wu.ftpd -l -a
pop-3 stream tcp nowait root /usr/sbin/tcpd \
        in.qpop -s
</PRE>
<P>A virtual /etc/inetd.conf file looks like this:
<P>
<PRE>
ftp stream tcp nowait root /usr/local/bin/virtuald \
        virtuald /virtual/conf.ftp wu.ftpd -l -a
pop-3 stream tcp nowait root /usr/local/bin/virtuald \
        virtuald /virtual/conf.pop in.qpop -s
</PRE>
<P>
<H2><A NAME="ss3.3">3.3 Config File</A>
</H2>

<P>Each service gets a config file that will control what IPs and 
directories are allowed for that service.  You can have one 
master config file or several config files if you want each service 
to get a different list of domains.   A config file looks like 
this:
<P>
<PRE>
# This is a comment and so are blank lines

# Format IP SPACE dir NOSPACES
10.10.10.129 /virtual/domain1.com
10.10.10.130 /virtual/domain2.com
10.10.10.157 /virtual/domain3.com

# Default option for all other IPs
default /
</PRE>
<P>
<H2><A NAME="ss3.4">3.4 Source</A>
</H2>

<P>This is the C source code to the virtuald program.  Compile it and
install it in /usr/local/bin with permission 0755, user root, and
group root.  The only compile option is VERBOSELOG which will turn
on/off logging of connections.
<P>
<PRE>
#include &lt;netinet/in.h&gt;
#include &lt;sys/socket.h&gt;
#include &lt;arpa/inet.h&gt;
#include &lt;stdarg.h&gt;
#include &lt;unistd.h&gt;
#include &lt;string.h&gt;
#include &lt;syslog.h&gt;
#include &lt;stdio.h&gt;

#undef VERBOSELOG

#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 *)&amp;virtual_addr,&amp;virtual_len)&lt;0)
        {
                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.49 $");
#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(&amp;ipaddr))
        {
                syslog(LOG_ERR,"getipaddr failed");
                exit(0);
        }
#ifdef VERBOSELOG
        syslog(LOG_ERR,"Incoming ip: %s",ipaddr);
#endif
        if (iptodir(&amp;dir,ipaddr,argv[1]))
        {
                syslog(LOG_ERR,"iptodir failed");
                exit(0);
        }
        if (chroot(dir)&lt;0)
        {
                syslog(LOG_ERR,"chroot failed: %m");
                exit(0);
        }
#ifdef VERBOSELOG
        syslog(LOG_ERR,"Chroot dir: %s",dir);
#endif
        if (chdir("/")&lt;0)
        {
                syslog(LOG_ERR,"chdir failed: %m");
                exit(0);
        }
        if (execvp(argv[2],argv+2)&lt;0)
        {
                syslog(LOG_ERR,"execvp failed: %m");
                exit(0);
        }

        closelog();

        exit(0);
}
</PRE>
<P>
<HR>
<A HREF="Virtual-Services-HOWTO-4.html">Next</A>
<A HREF="Virtual-Services-HOWTO-2.html">Previous</A>
<A HREF="Virtual-Services-HOWTO.html#toc3">Contents</A>
</BODY>
</HTML>