#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <string.h>
#include <linux/socket.h>
#include <net/if.h>
#include <linux/if_tun.h>

#define max(a,b) ((a)>(b) ? (a):(b))

int tun_alloc(char * buf)
{
  struct ifreq ifr;
  int fd, err;
  {
    char name[1024];
    sprintf(name, "/dev/net/%s", buf);
    if( (fd = open(name, O_RDWR)) < 0 ) {
      char err[1024];
      sprintf(err, "Failed to open %s.", buf);
      perror(err);
      exit(-1);
    }
  }
  memset(&ifr, 0, sizeof(ifr));

  /* Flags: IFF_TUN   - TUN device (no Ethernet headers) 
   *        IFF_TAP   - TAP device  
   *
   *        IFF_NO_PI - Do not provide packet information  
   */ 
  //ifr.ifr_flags = IFF_NO_PI;
  ifr.ifr_flags = IFF_TUN; 
  if( *buf )
    strncpy(ifr.ifr_name, buf, IFNAMSIZ);

  if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){ 
    char err[1024]; 
    close(fd); 
    sprintf(err, "Failed to TUNSETIFF %s.", buf); 
    perror(err); 
    exit(-1); 
  } 
  strcpy(buf, ifr.ifr_name); 
  return fd;
}              

int main(int argc, char *argv[])
{
  char buf[4096];
  int f1,l;
  fd_set fds;
 
  if (argc < 2) {
    printf("Usage: bridge tap|tun\n");
    exit(1);
  }

  sprintf(buf,"%s",argv[1]);
  f1 = tun_alloc(buf);
  ioctl(f1, TUNSETNOCSUM, 1); 

  while(1){
    FD_ZERO(&fds);
    FD_SET(f1, &fds);
    FD_SET(0, &fds);

    select(f1 + 1, &fds, NULL, NULL, NULL);

    if( FD_ISSET(f1, &fds) ) {
      l = read(f1,buf,sizeof(buf));
      write(1,buf,l);
    }
    if( FD_ISSET(0, &fds) ) {
      l = read(0,buf,sizeof(buf));
      write(f1,buf,l);
    }
  }
}
