/* Copyright 2004 Renzo Davoli
* Reseased under the GPLv2 */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/stat.h>
#include <limits.h>
#include <dlfcn.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/if_tun.h>
#define TUNTAPPATH "/dev/tap"
#define VDETAPEXEC "vdetap"
#define VDEALLTAP "VDEALLTAP"
#define MAX 10
#if defined(RTLD_NEXT)
#define REAL_LIBC RTLD_NEXT
#else
#define REAL_LIBC ((void *) -1L)
#endif
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__bsdi__)
typedef unsigned long request_t;
#else
typedef int request_t;
#endif
int tapfd[2] = {-1,-1};
static int tapcount=0;
static struct pidlist {
pid_t pid;
struct pidlist *next;
} *plh = NULL, *flh=NULL, pidpool[MAX];
static struct pidlist *plmalloc(void) {
struct pidlist *rv;
rv=flh;
if (rv != NULL)
flh=flh->next;
return rv;
}
static int addpid(int pid) {
struct pidlist *plp;
if ((plp=plmalloc ()) != NULL) {
plp->next=plh;
plh=plp;
plp->pid=pid;
return pid;
} else {
kill(pid,SIGTERM);
return -1;
}
}
void _init(void)
{
register int i;
for (i=1;i<MAX;i++)
pidpool[i-1].next= &(pidpool[i]);
flh=pidpool;
}
void _fini(void)
{
struct pidlist *plp=plh;
while (plp != NULL) {
kill(plp->pid,SIGTERM);
plp = plp->next;
}
}
int open(const char *path, int flags, ...)
{
static int (*func) (const char *, int, mode_t) = NULL;
char *vdesock;
int pid;
va_list ap;
mode_t data;
if (!func)
func = (int (*) (const char *, int, mode_t))
dlsym (REAL_LIBC, "open");
va_start(ap, flags);
data = va_arg(ap, int);
va_end(ap);
if (strcmp(path,TUNTAPPATH)==0 && tapfd[0] == -1) {
if (socketpair(PF_UNIX, SOCK_DGRAM, 0,tapfd) == 0) {
char num[5];
char name[10];
sprintf(name,"tap%d",tapcount++);
if (((vdesock=getenv(name)) != NULL)
||(vdesock=getenv(VDEALLTAP)) != NULL){
if ((pid=fork()) < 0) {
close(tapfd[1]);
errno=EINVAL;
return -1;
} else if (pid > 0) { /*father*/
if((pid=addpid(pid)) < 0) {
close(tapfd[0]);
close(tapfd[1]);
return -1;
} else {
close(tapfd[1]);
return tapfd[0];
}
} else { /*son*/
plh=NULL;
close(tapfd[0]);
sprintf(num,"%d",tapfd[1]);
execlp(VDETAPEXEC,"-",num,vdesock,(char *) 0);
}
}
return tapfd[0];
}
else
return -1;
} else
return (*func)(path, flags, data);
}
int ioctl(int fd, unsigned long int command, ...)
{
static int (*func) (int, request_t, void *) = NULL;
int dummy;
va_list ap;
char *data;
struct ifstat *ifs;
if (!func)
func = (int (*) (int, request_t, void *))
dlsym (REAL_LIBC, "ioctl");
va_start(ap, command);
data = va_arg(ap, char *);
va_end(ap);
if (fd == tapfd[0]) {
switch(command) {
case SIOCSIFFLAGS:
case SIOCADDMULTI:
case SIOCDELMULTI:
break;
case SIOCGIFSTATUS:
ifs = (struct ifstat *)data;
dummy = strlen(ifs->ascii);
if(plh && dummy < sizeof(ifs->ascii))
snprintf(ifs->ascii + dummy,
sizeof(ifs->ascii) - dummy,
"\tOpened by PID %d\n",
plh[0].pid);
break;
default:
return (*func) (fd, command, data);
}
}
return (*func) (fd, command, data);
}
syntax highlighted by Code2HTML, v. 0.9.1