//Russ Handorf wrote most of this in a fit of rage. 
//Mike, all the love in the world for putting up with me and my bad coding.
//Demo code pulled from LORCON man pages and examples (thanks Brad Antoniewicz!)
//Run this at your own peril. It's bad code. Honest.

#include <stdio.h>
#include <getopt.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <lorcon2/lorcon.h>
#include <lorcon2/lorcon_packasm.h>
#include <inttypes.h>
#include <math.h>

void help() {
  printf("There's really only one option right now:\n");
  printf("\t-i <int> \tInterface\n");
}

void random_ssid(char *ssid) {
  int i, len;
  srand(time(NULL) + getpid());  //replace me im shit: fopen /dev/urandom in rb mode then fread(in_mac, 6, 1, fileptr)
  len=rand() % 31;
  static const char alphanum[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 ";

  for (i = 0; i < len; i++) {
    ssid[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
  }
  ssid[len] = 0;
}

void random_mac(uint8_t mac[6]){
  int i;
  srand(time(NULL) + getpid());  //replace me im shit: fopen /dev/urandom in rb mode then fread(in_mac, 6, 1, fileptr) 

  for (i = 0; i < 6; i++) {
    mac[i] = rand() % 256;
  }
}

int main(int argc, char *argv[]) {
  char *interface = NULL;
  char ssid[32];
  int c;
  lorcon_driver_t *drvlist, *driver;
  lorcon_t *context;
  lcpa_metapack_t *metapack;
  lorcon_packet_t *txpack;
  uint8_t src_mac[6], dst_mac[6];

  struct timeval time2; 
  uint64_t timestamp;
  int interval = 10;
  int capabilities = 0x0421;

  int channel=1;

  long ms; // Milliseconds
  time_t s;  // Seconds
  struct timespec spec;

  int randompacket=rand()%3;
  char *packettype="UNK";

  while ((c = getopt(argc, argv, "i:h")) != EOF) {
    switch (c) {
      case 'i': 
        interface = strdup(optarg);
        break;
      case 'h':
        help();
        return(0);
        break;
    }
  }

  if ( interface == NULL ) { 
    printf ("ERROR: Interface not set.\n");
    help();
    return(-1);
  }

  if ( (driver = lorcon_auto_driver(interface)) == NULL) {
    printf("[!] Could not determine the driver for %s\n",interface);
    return -1;
  } else {
    printf("[+]\t Driver: %s\n",driver->name);
  }


  if ((context = lorcon_create(interface, driver)) == NULL) {
    printf("[!]\t Failed to create context");
    return -1; 
  }

  if (lorcon_open_injmon(context) < 0) {
    printf("[!]\t Could not create Monitor Mode interface!\n");
    return -1;
  } else {
    printf("[+]\t Monitor Mode VAP: %s\n",lorcon_get_vap(context));
    lorcon_free_driver_list(driver);
  }

  int tmpchan=0;
  int finalchannels[255];
  int channels24[15]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14};
  int channels52[10]={0,36,40,44,48,52,56,60,64};
  int channels58[17]={0,100,104,108,112,116,120,124,128,132,136,140,149,153,157,161,165};
  uint8_t rates[] = "\x8c\x12\x98\x24\xb0\x48\x60\x6c";
  int chancount=0;
  int tmpcode=0;


  //technically, I dont need the loops below anymore, and can just go from 1 to the max since it all goes in the array anyways
  //he said after recovering from mucinex dm
  int chanmax=sizeof(channels24) / sizeof(int);
  for (tmpchan=1; tmpchan<chanmax; tmpchan++) {
    //printf("Setting channel %d\n", channels24[tmpchan]);
    tmpcode = lorcon_set_channel(context,channels24[tmpchan]);
    if (tmpcode == 0) {
      channels24[0]=1;
      finalchannels[chancount]=channels24[tmpchan];
      chancount++;
    }
  }
  chanmax=sizeof(channels52) / sizeof(int);
  for (tmpchan=1; tmpchan<chanmax; tmpchan++) {
    tmpcode = lorcon_set_channel(context,channels52[tmpchan]);
    if (tmpcode == 0) {
      channels52[0]=1;
      finalchannels[chancount]=channels52[tmpchan];
      chancount++;
    }
  }
  chanmax=sizeof(channels58) / sizeof(int);
  for (tmpchan=1; tmpchan<chanmax; tmpchan++) {
    tmpcode = lorcon_set_channel(context,channels58[tmpchan]);
    if (tmpcode == 0) {
      channels58[0]=1;
      finalchannels[chancount]=channels58[tmpchan];
      chancount++;
    }
  }

  if (channels24[0]==1) {
    printf("[+]\t Enabling 2.4\n");
  } else {
    printf("[+]\t DISABLING 2.4\n");
  }

  if (channels52[0]==1) {
    printf("[+]\t Enabling 5.2\n");
  } else {
    printf("[+]\t DISABLING 5.2\n");
  }

  if (channels58[0]==1) {
    printf("[+]\t Enabling 5.8\n");
  } else {
    printf("[+]\t DISABLING 5.8\n");
  }

  printf("[+]\t Enabling a total of %d channels\n", chancount);
  int count=0;

  srand(time(NULL) + getpid());

  FILE * logs;
  logs = fopen ("eventlogs.txt","w");
  fprintf (logs,"TIME, TYPE, SRC MAC, DST MAC, CHANNEL, SSID\n");

  while(1) {
    // Create timestamp
    clock_gettime(CLOCK_REALTIME, &spec);
    s  = spec.tv_sec;
    ms = round(spec.tv_nsec / 1.0e6); // Convert nanoseconds to milliseconds
    if (ms > 999) {
      s++;
      ms = 0;
    }
    gettimeofday(&time2, NULL);
    timestamp = time2.tv_sec * 1000000 + time2.tv_usec;

    // Initialize the LORCON metapack       
    metapack = lcpa_init();

    // Create a Beacon frame from 00:DE:AD:BE:EF:00
    random_mac(src_mac);
    random_mac(dst_mac);
    random_ssid(ssid);

    channel = finalchannels[rand() % (chancount)];
    lorcon_set_channel(context,channel);

    randompacket=rand()%3;
    switch(randompacket) {
      case 0:
        packettype="BEACON";
        lcpf_beacon(metapack, src_mac, dst_mac, 0x00, 0x00, 0x00, 0x00, timestamp, interval, capabilities);
        break;
      case 1:
        packettype="PROBE REQUEST";
        lcpf_probereq(metapack, src_mac, 0x00, 0x00, 0x00, 0x00);
        break;
      case 2:
        packettype="PROBE RESPONSE";
        lcpf_proberesp(metapack, dst_mac, src_mac, src_mac, 0x00, 0x00, 0x00, 0x00, timestamp, interval, capabilities);
        break;
    }

    // Append IE Tag 0 for SSID
    lcpf_add_ie(metapack, 0, strlen(ssid),ssid);

    // Most of the following IE tags are not needed, but added here as examples

    // Append IE Tag 1 for rates
    lcpf_add_ie(metapack, 1, sizeof(rates)-1, rates);

    // Append IE Tag 3 for Channel 
    lcpf_add_ie(metapack, 3, 1, &channel);

    // Append IE Tags 42/47 for ERP Info 
    lcpf_add_ie(metapack, 42, 1, "\x05");
    lcpf_add_ie(metapack, 47, 1, "\x05");
        
    // Convert the LORCON metapack to a LORCON packet for sending
    txpack = (lorcon_packet_t *) lorcon_packet_from_lcpa(context, metapack);

    if ( lorcon_inject(context,txpack) < 0 )
      return -1;

    usleep(interval * 1000);

    printf("\033[K\r");
    fprintf(logs,"%"PRIdMAX".%03ld, %s, %02x:%02x:%02x:%02x:%02x:%02x, %02x:%02x:%02x:%02x:%02x:%02x, %d, %s\n", (intmax_t)s, ms, packettype, src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5], dst_mac[0], dst_mac[1], dst_mac[2], dst_mac[3], dst_mac[4], dst_mac[5], channel, ssid);
    printf("[+] Src Mac: %02x:%02x:%02x:%02x:%02x:%02x  Dst Mac: %02x:%02x:%02x:%02x:%02x:%02x  C: %d  Sent %d frames, Hit CTRL + C to stop...", src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5], dst_mac[0], dst_mac[1], dst_mac[2], dst_mac[3], dst_mac[4], dst_mac[5], channel, count);
    fflush(stdout);
    count++;

    // Free the metapack
    lcpa_free(metapack);

  }

  fclose(logs);
  lorcon_close(context);
  lorcon_free(context);
  return(0);
}
