Logo Search packages:      
Sourcecode: vde2 version File versions  Download package

libvdetap.c

/* Copyright 2004 Renzo Davoli
 * Reseased under the GPLv2 */

#define _GNU_SOURCE
#include <config.h>
#include <dlfcn.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <linux/ioctl.h>
#include <linux/if.h>
#include <linux/if_tun.h>

#define TUNTAPPATH "/dev/net/tun"
#define VDETAPEXEC LIBEXECDIR "/vdetap"
#define VDEALLTAP "VDEALLTAP"
#define MAX 10

#define nativesym(function, name) \
    { \
        char *msg; \
      if (native_##function == NULL) { \
          *(void **)(&native_##function) = dlsym(RTLD_NEXT, name); \
          if ((msg = dlerror()) != NULL) { \
            fprintf (stderr, "%s: dlsym(%s): %s\n", PACKAGE, name, msg); \
          } \
      } \
    }

static int     (*native_ioctl) (int d, int request, ...) = NULL;
static int     (*native_open) (const char *pathname, int flags, ...) = NULL;
static int     (*native_open64) (const char *pathname, int flags, ...) = NULL;

int tapfd[2] = {-1,-1};
static int tapcount=0;
static int tuncount=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 void plfree (struct pidlist *el) {
      el->next=flh;
      flh=el;
}

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 libvdetap_init (void) __attribute((constructor));
void libvdetap_init(void)
{
      register int i;
      nativesym(ioctl, "ioctl");
      nativesym(open, "open");
      nativesym(open64, "open64");
      for (i=1;i<MAX;i++) 
            pidpool[i-1].next= &(pidpool[i]);
      flh=pidpool;
}

void libvdetap_fini(void)
{
      struct pidlist *plp=plh;
      while (plp != NULL) {
            kill(plp->pid,SIGTERM);
            plp = plp->next;
      }
}

int open(const char *path, int flags, ...)
{
      static char buf[PATH_MAX];
      va_list ap;
      mode_t data;

      va_start(ap, flags);
      data = va_arg(ap, mode_t);
      va_end(ap);

      if (strcmp(path,TUNTAPPATH)==0 && tapfd[0] == -1) {
            if (socketpair(PF_UNIX, SOCK_DGRAM, 0,tapfd) == 0) {
                  return tapfd[0];
            }
            else
                  return -1;

      } else
            return native_open(path, flags, data);
}

int open64(const char *path, int flags, ...)
{
      static char buf[PATH_MAX];
      va_list ap;
      mode_t data;

      va_start(ap, flags);
      data = va_arg(ap, mode_t);
      va_end(ap);

      if (strcmp(path,TUNTAPPATH)==0 && tapfd[0] == -1) {
            if (socketpair(PF_UNIX, SOCK_DGRAM, 0,tapfd) == 0) {
                  return tapfd[0];
            }
            else
                  return -1;

      } else
            return native_open64(path, flags | O_LARGEFILE, data);
}

int ioctl(int fd, unsigned long int command, ...)
{
      va_list ap;
      char *data;
      char *vdesock;
      int pid;

      va_start(ap, command);
      data = va_arg(ap, char *);
      va_end(ap);

      if (fd == tapfd[0]) {
            if (command == TUNSETIFF) {
                  struct ifreq *ifr = (struct ifreq *) data;
                  char num[5];
                  char name[10];

                  ifr->ifr_name[IFNAMSIZ-1] = '\0';
                  if (ifr->ifr_name[0] == 0) {
                        if (ifr->ifr_flags & IFF_TAP) 
                              sprintf(name,"tap%d",tapcount++);
                        else
                              sprintf(name,"tun%d",tuncount++);
                        strncpy(ifr->ifr_name,name,IFNAMSIZ);
                  }
                  else if (strchr(ifr->ifr_name, '%') != NULL) {
                        sprintf(name,ifr->ifr_name,tapcount++);
                        strncpy(ifr->ifr_name,name,IFNAMSIZ);
                  }
                  if (ifr->ifr_flags & IFF_TAP &&
                              ((vdesock=getenv(ifr->ifr_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 0;
                              }
                        } else { /*son*/
                              plh=NULL;
                              close(tapfd[0]);
                              sprintf(num,"%d",tapfd[1]);
                              execlp(VDETAPEXEC,"-",num,vdesock,name,(char *) 0);
                        }
                  }
                  else /*roll back to the native tuntap*/
                  {
                        int newfd;
                        int saverrno;
                        int resultioctl;
                        close(tapfd[1]);
                        if ((newfd=native_open(TUNTAPPATH,  O_RDWR, 0)) < 0) {
                              saverrno=errno;
                              close(tapfd[0]);
                              errno=saverrno;
                              return -1;
                        } else
                        {
                              resultioctl=native_ioctl(fd, command, data);
                              if (resultioctl < 0) {
                                    saverrno=errno;
                                    close(tapfd[0]);
                                    errno=saverrno;
                                    return -1;
                              } else {
                                    dup2(newfd,tapfd[0]);
                                    return resultioctl;
                              }
                        }
                  }
            }                 else 
                  return 0;
      } else
            return (native_ioctl(fd, command, data));
}


Generated by  Doxygen 1.6.0   Back to index