241 lines
7.1 KiB
HTML
241 lines
7.1 KiB
HTML
<!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 <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>
|
|
|
|
#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 *)&virtual_addr,&virtual_len)<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(&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);
|
|
}
|
|
</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>
|