#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/if_ether.h>

#define ENV_SOCK "SOCK_FD"
#define ENV_SOCK1 "SOCK_FD1"

extern char **environ;

void usage() {
  fprintf(stderr,"Usage:  launch [-m 0-3] application <args>\n\n");
  fprintf(stderr,"Mode 0: raw packet socket\n");
  fprintf(stderr,"Mode 1: cooked packet socket\n");
  fprintf(stderr,"Mode 2: raw IP socket\n");
  fprintf(stderr,"Mode 3: a raw packet socket and a raw IP socket\n");
  exit(1);
}

int main(int argc, char** argv){

  int sockfd, mode;
  int sockfd1;
  char **args;
  char s[32], opt;

  /* check args */
  if ((opt = getopt(argc, argv, "m:")) > 0) {
	printf("OPT=%c\n",opt);
    switch (opt) { 
    case 'm':
      mode = atoi(optarg);
      break;
    default:
      usage();
    }
  }
  if (optind >= argc)
    usage();

  /* Open a socket */
  switch (mode) {
  case 0:
    sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    break;
  case 1:
    sockfd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL));
    break;
  case 2:
    sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    break;
  case 3:
    sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    sockfd1 = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 
    break;
  default:
    usage();
  }
  if (sockfd < 0) {
    fprintf(stderr,"Could not open socket\n");
    exit(1);
  }

  /* add socket fd to environment */
  sprintf(s, "%s=%i", ENV_SOCK, sockfd);
  putenv(s);
  sprintf(s, "%s=%i", ENV_SOCK1, sockfd1);
  putenv(s);

  /* Drop root privileges. */
  if (setuid(getuid()) == -1){
    fprintf(stderr,"Could not drop root privileges\n");
    exit(1);
  }

  /* set arguments for new process */
  args = argv + optind;

  /* Exec the file specified on cmdline */
  execve(argv[optind], args, environ);
  
  /* Should never get here */
  fprintf (stderr, "Could not execute %s\n",args[0]);
  return 1;
}
