Imported Upstream version 0.5.2 debian upstream upstream/0.5.2
authorDevon Kearns <dookie@kali.org>
Thu, 27 Dec 2012 14:38:42 +0000 (07:38 -0700)
committerDevon Kearns <dookie@kali.org>
Thu, 27 Dec 2012 14:38:42 +0000 (07:38 -0700)
CHANGELOG [new file with mode: 0644]
README [new file with mode: 0644]
bdaddr.c [new file with mode: 0644]
btdev.h [new file with mode: 0644]
dev_class.c [new file with mode: 0644]
makefile [new file with mode: 0755]
namelist.c [new file with mode: 0644]
oui.c [new file with mode: 0644]
oui.h [new file with mode: 0644]
spooftooph.c [new file with mode: 0644]

diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644 (file)
index 0000000..9a1bbcf
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,45 @@
+v0.5.2
+- Added -B flag to remove the banner.  Easier to use on small screens.
+
+v0.5.1
+- Fixed bug in variable name "class" causing conflict name issues.
+
+v0.5
+- Fixed segmentation fault in manual assigning of Device Name and Class of Device
+- Modified flags
+  - Depreciated
+    -r: Assign random NAME, CLASS, and ADDR
+    -l <log>: Load SpoofTooph CSV logfile
+    -d <log>: Dump scan into SpoofTooph CSV logfile
+  - New
+    -w <file>: Write to CSV file
+    -r <file>: Read from CSV file
+    -R: Assign random NAME, CLASS, and ADDR
+    -m: Specify multiple interfaces during selection
+    -u: USB delay.  Interactive delay for reinitializing interfaces
+
+v0.4.1 - 06/15/2011
+- Took out some testing code
+
+v0.4 - 03/24/2011
+- Save file on exit.
+- Fixed problem with saving log.
+- Fixed problem with closing threads.
+- Changed probes for device name.  Scan runs much much faster now.
+
+v0.3
+- Fixed socket closing error
+- Fixed log data verification for valid ADDR and CLASS
+- Changed logging format to CSV: ADDR,CLASS,NAME
+- Added -m flag for choosing multiple interfaces to use for cloning 
+  (Useful to test Man-In-The-Middle attacks)
+- Fixed the problem with reading in the Class from a log
+- Fixed overflow problem with array of devices
+- Fixed selection of Bluetooth interface from a always using
+  interface hci0
+- Changed device array to dynmically resize
+- Added -b flag for specifying the number of Bluetooth devices
+  to display per page
+
+v0.1
+- Initial release
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..3df0c32
--- /dev/null
+++ b/README
@@ -0,0 +1,103 @@
+  spooftooph
+
+Copyright (C) 2009-2011 Shadow Cave LLC
+
+Written 2009-2011 by JP Dunning (.ronin)
+ronin [ at ] shadowcave [dt] org
+<www.hackfromacave.com>
+
+  License
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation;
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY 
+CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS 
+DISCLAIMED.
+
+
+
+  ABOUT
+
+Spooftooph is designed to automate spoofing or cloning Bluetooth device 
+Name, Class, and Address.  See 'Usage' for more information of its capabilities.
+
+
+
+  INSTALL
+
+1. Run "make" to compile binaries.
+2. Run "make install" to install into system.
+3. Run "make clean" to delete binaries from spooftooph directory.
+
+
+
+  RESOURCES
+
+- BlueZ
+- BlueZ-devel
+- ncurses
+- ncurses-devel 
+
+
+
+  USAGE
+
+To modify the Bluetooth adapter, spooftooth must be run with root privileges.  
+Spooftooph offers five modes of usage:
+
+ 1) Specify NAME, CLASS and ADDR.
+
+> spooftooph -i hci0 -n new_name -a 00:11:22:33:44:55 -c 0x1c010c
+
+ 2) Randomly generate NAME, CLASS and ADDR.
+
+> spooftooph -i hci0 -r
+
+ 3) Scan for devices in range and select device to clone.  Optionally dump the device 
+ information in a specified log file.
+
+> spooftooph -i hci0 -s -d file.log
+
+ 4) Load in device info from log file and specify device info to clone.
+
+> spooftooph -i hci0 -l file.log
+
+ 5) Clone a random devices info in range every X seconds.
+
+> spooftooph -i hci0 -t 10
+
+
+
+  HELP
+
+NAME
+        spooftooph
+
+SYNOPSIS
+        spooftooph -i dev [-m] [-sd] [-nac] [-r] [-l] [-t]
+
+DESCRIPTION
+        -a <address>    : Specify new ADDR
+        -b <num_lines>  : Number of Bluetooth profiles to display per page
+        -c <class>      : Specify new CLASS
+        -d <log>        : Dump scan into log file
+        -h              : Help
+        -i <dev>        : Specify interface
+        -l <log>        : Load a list of Bluetooth profiles to clone from saved log
+        -n <name>       : Specify new NAME
+        -m              : Specify multiple interfaces durring selection.
+        -r              : Assign random NAME, CLASS, and ADDR
+        -s              : Scan for devices in local area
+        -t <time>       : Time interval to clone device in range
\ No newline at end of file
diff --git a/bdaddr.c b/bdaddr.c
new file mode 100644 (file)
index 0000000..92cb9bc
--- /dev/null
+++ b/bdaddr.c
@@ -0,0 +1,441 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *  Modified by JP Dunning (.ronin) 2010 <ronin [ at ] shadowcave [dt] org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "oui.h"
+
+static int transient = 0;
+
+static int generic_reset_device(int dd)
+{
+       bdaddr_t bdaddr;
+       int err;
+
+       err = hci_send_cmd(dd, 0x03, 0x0003, 0, NULL);
+       if (err < 0)
+               return err;
+
+       return hci_read_bd_addr(dd, &bdaddr, 10000);
+}
+
+#define OCF_ERICSSON_WRITE_BD_ADDR     0x000d
+typedef struct {
+       bdaddr_t        bdaddr;
+} __attribute__ ((packed)) ericsson_write_bd_addr_cp;
+#define ERICSSON_WRITE_BD_ADDR_CP_SIZE 6
+
+static int ericsson_write_bd_addr(int dd, bdaddr_t *bdaddr)
+{
+       struct hci_request rq;
+       ericsson_write_bd_addr_cp cp;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.bdaddr, bdaddr);
+
+       memset(&rq, 0, sizeof(rq));
+       rq.ogf    = OGF_VENDOR_CMD;
+       rq.ocf    = OCF_ERICSSON_WRITE_BD_ADDR;
+       rq.cparam = &cp;
+       rq.clen   = ERICSSON_WRITE_BD_ADDR_CP_SIZE;
+       rq.rparam = NULL;
+       rq.rlen   = 0;
+
+       if (hci_send_req(dd, &rq, 1000) < 0)
+               return -1;
+
+       return 0;
+}
+
+#define OCF_ERICSSON_STORE_IN_FLASH    0x0022
+typedef struct {
+       uint8_t         user_id;
+       uint8_t         flash_length;
+       uint8_t         flash_data[253];
+} __attribute__ ((packed)) ericsson_store_in_flash_cp;
+#define ERICSSON_STORE_IN_FLASH_CP_SIZE 255
+
+static int ericsson_store_in_flash(int dd, uint8_t user_id, uint8_t flash_length, uint8_t *flash_data)
+{
+       struct hci_request rq;
+       ericsson_store_in_flash_cp cp;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.user_id = user_id;
+       cp.flash_length = flash_length;
+       if (flash_length > 0)
+               memcpy(cp.flash_data, flash_data, flash_length);
+
+       memset(&rq, 0, sizeof(rq));
+       rq.ogf    = OGF_VENDOR_CMD;
+       rq.ocf    = OCF_ERICSSON_STORE_IN_FLASH;
+       rq.cparam = &cp;
+       rq.clen   = ERICSSON_STORE_IN_FLASH_CP_SIZE;
+       rq.rparam = NULL;
+       rq.rlen   = 0;
+
+       if (hci_send_req(dd, &rq, 1000) < 0)
+               return -1;
+
+       return 0;
+}
+
+static int csr_write_bd_addr(int dd, bdaddr_t *bdaddr)
+{
+       unsigned char cmd[] = { 0x02, 0x00, 0x0c, 0x00, 0x11, 0x47, 0x03, 0x70,
+                               0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+       unsigned char cp[254], rp[254];
+       struct hci_request rq;
+
+       if (transient)
+               cmd[14] = 0x08;
+
+       cmd[16] = bdaddr->b[2];
+       cmd[17] = 0x00;
+       cmd[18] = bdaddr->b[0];
+       cmd[19] = bdaddr->b[1];
+       cmd[20] = bdaddr->b[3];
+       cmd[21] = 0x00;
+       cmd[22] = bdaddr->b[4];
+       cmd[23] = bdaddr->b[5];
+
+       memset(&cp, 0, sizeof(cp));
+       cp[0] = 0xc2;
+       memcpy(cp + 1, cmd, sizeof(cmd));
+
+       memset(&rq, 0, sizeof(rq));
+       rq.ogf    = OGF_VENDOR_CMD;
+       rq.ocf    = 0x00;
+       rq.event  = EVT_VENDOR;
+       rq.cparam = cp;
+       rq.clen   = sizeof(cmd) + 1;
+       rq.rparam = rp;
+       rq.rlen   = sizeof(rp);
+
+       if (hci_send_req(dd, &rq, 2000) < 0)
+               return -1;
+
+       if (rp[0] != 0xc2) {
+               errno = EIO;
+               return -1;
+       }
+
+       if ((rp[9] + (rp[10] << 8)) != 0) {
+               errno = ENXIO;
+               return -1;
+       }
+
+       return 0;
+}
+
+static int csr_reset_device(int dd)
+{
+       unsigned char cmd[] = { 0x02, 0x00, 0x09, 0x00,
+                               0x00, 0x00, 0x01, 0x40, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+       unsigned char cp[254], rp[254];
+       struct hci_request rq;
+
+       if (transient)
+               cmd[6] = 0x02;
+
+       memset(&cp, 0, sizeof(cp));
+       cp[0] = 0xc2;
+       memcpy(cp + 1, cmd, sizeof(cmd));
+
+       memset(&rq, 0, sizeof(rq));
+       rq.ogf    = OGF_VENDOR_CMD;
+       rq.ocf    = 0x00;
+       rq.event  = EVT_VENDOR;
+       rq.cparam = cp;
+       rq.clen   = sizeof(cmd) + 1;
+       rq.rparam = rp;
+       rq.rlen   = sizeof(rp);
+
+       if (hci_send_req(dd, &rq, 2000) < 0)
+               return -1;
+
+       return 0;
+}
+
+#define OCF_TI_WRITE_BD_ADDR           0x0006
+typedef struct {
+       bdaddr_t        bdaddr;
+} __attribute__ ((packed)) ti_write_bd_addr_cp;
+#define TI_WRITE_BD_ADDR_CP_SIZE 6
+
+static int ti_write_bd_addr(int dd, bdaddr_t *bdaddr)
+{
+       struct hci_request rq;
+       ti_write_bd_addr_cp cp;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.bdaddr, bdaddr);
+
+       memset(&rq, 0, sizeof(rq));
+       rq.ogf    = OGF_VENDOR_CMD;
+       rq.ocf    = OCF_TI_WRITE_BD_ADDR;
+       rq.cparam = &cp;
+       rq.clen   = TI_WRITE_BD_ADDR_CP_SIZE;
+       rq.rparam = NULL;
+       rq.rlen   = 0;
+
+       if (hci_send_req(dd, &rq, 1000) < 0)
+               return -1;
+
+       return 0;
+}
+
+#define OCF_BCM_WRITE_BD_ADDR          0x0001
+typedef struct {
+       bdaddr_t        bdaddr;
+} __attribute__ ((packed)) bcm_write_bd_addr_cp;
+#define BCM_WRITE_BD_ADDR_CP_SIZE 6
+
+static int bcm_write_bd_addr(int dd, bdaddr_t *bdaddr)
+{
+       struct hci_request rq;
+       bcm_write_bd_addr_cp cp;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.bdaddr, bdaddr);
+
+       memset(&rq, 0, sizeof(rq));
+       rq.ogf    = OGF_VENDOR_CMD;
+       rq.ocf    = OCF_BCM_WRITE_BD_ADDR;
+       rq.cparam = &cp;
+       rq.clen   = BCM_WRITE_BD_ADDR_CP_SIZE;
+       rq.rparam = NULL;
+       rq.rlen   = 0;
+
+       if (hci_send_req(dd, &rq, 1000) < 0)
+               return -1;
+
+       return 0;
+}
+
+#define OCF_ZEEVO_WRITE_BD_ADDR                0x0001
+typedef struct {
+       bdaddr_t        bdaddr;
+} __attribute__ ((packed)) zeevo_write_bd_addr_cp;
+#define ZEEVO_WRITE_BD_ADDR_CP_SIZE 6
+
+static int zeevo_write_bd_addr(int dd, bdaddr_t *bdaddr)
+{
+       struct hci_request rq;
+       zeevo_write_bd_addr_cp cp;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.bdaddr, bdaddr);
+
+       memset(&rq, 0, sizeof(rq));
+       rq.ogf    = OGF_VENDOR_CMD;
+       rq.ocf    = OCF_ZEEVO_WRITE_BD_ADDR;
+       rq.cparam = &cp;
+       rq.clen   = ZEEVO_WRITE_BD_ADDR_CP_SIZE;
+       rq.rparam = NULL;
+       rq.rlen   = 0;
+
+       if (hci_send_req(dd, &rq, 1000) < 0)
+               return -1;
+
+       return 0;
+}
+
+static int st_write_bd_addr(int dd, bdaddr_t *bdaddr)
+{
+       return ericsson_store_in_flash(dd, 0xfe, 6, (uint8_t *) bdaddr);
+}
+
+static struct {
+       uint16_t compid;
+       int (*write_bd_addr)(int dd, bdaddr_t *bdaddr);
+       int (*reset_device)(int dd);
+} vendor[] = {
+       { 0,            ericsson_write_bd_addr, NULL                    },
+       { 10,           csr_write_bd_addr,      csr_reset_device        },
+       { 13,           ti_write_bd_addr,       NULL                    },
+       { 15,           bcm_write_bd_addr,      generic_reset_device    },
+       { 18,           zeevo_write_bd_addr,    NULL                    },
+       { 48,           st_write_bd_addr,       generic_reset_device    },
+       { 57,           ericsson_write_bd_addr, generic_reset_device    },
+       { 65535,        NULL,                   NULL                    },
+};
+
+/*static void usage(void)
+{
+       printf("bdaddr - Utility for changing the Bluetooth device address\n\n");
+       printf("Usage:\n"
+               "\tbdaddr [-i <dev>] [-r] [-t] [new bdaddr]\n");
+}
+*/
+static struct option main_options[] = {
+       { "device",     1, 0, 'i' },
+       { "reset",      0, 0, 'r' },
+       { "transient",  0, 0, 't' },
+       { "help",       0, 0, 'h' },
+       { 0, 0, 0, 0 }
+};
+
+
+/* Modifide by JP Dunning (.ronin)
+ *
+ * All modifications to btaddr.c are made in the following function.
+ * Modification were made to allow the functionality in the following
+ * function to be called from another application.
+ */
+static int cmd_bdaddr(int dev, char * new_addr)
+//int main(int argc, char **argv)
+{
+  struct hci_dev_info di;
+       struct hci_version ver;
+       bdaddr_t bdaddr;
+       char addr[18], oui[9], *comp;
+       int i, dd, opt, reset = 1;
+
+       bacpy(&bdaddr, BDADDR_ANY);
+
+       optind = 0;
+
+       dd = hci_open_dev(dev);
+       if (dd < 0) {
+               fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
+                                               dev, strerror(errno), errno);
+               return(1);
+       }
+
+       if (hci_devinfo(dev, &di) < 0) {
+               fprintf(stderr, "Can't get device info for hci%d: %s (%d)\n",
+                                               dev, strerror(errno), errno);
+               hci_close_dev(dd);
+               return(1);
+       }
+
+       if (hci_read_local_version(dd, &ver, 1000) < 0) {
+               fprintf(stderr, "Can't read version info for hci%d: %s (%d)\n",
+                                               dev, strerror(errno), errno);
+               hci_close_dev(dd);
+               return(1);
+       }
+
+       if (!bacmp(&di.bdaddr, BDADDR_ANY)) {
+               if (hci_read_bd_addr(dd, &bdaddr, 1000) < 0) {
+                       fprintf(stderr, "Can't read address for hci%d: %s (%d)\n",
+                                               dev, strerror(errno), errno);
+                       hci_close_dev(dd);
+                       return(1);
+               }
+       } else
+               bacpy(&bdaddr, &di.bdaddr);
+
+       printf("Manufacturer:   %s (%d)\n",
+                       bt_compidtostr(ver.manufacturer), ver.manufacturer);
+
+       ba2oui(&bdaddr, oui);
+       comp = ouitocomp(oui);
+
+       ba2str(&bdaddr, addr);
+       printf("Device address: %s", addr);
+
+       if (comp) {
+               printf(" (%s)\n", comp);
+               free(comp);
+       } else
+               printf("\n");
+
+/*     if (argc < 1) {
+               hci_close_dev(dd);
+               return(0);
+       }
+*/
+       str2ba(new_addr, &bdaddr);
+       if (!bacmp(&bdaddr, BDADDR_ANY)) {
+               hci_close_dev(dd);
+               return(0);
+       }
+       for (i = 0; vendor[i].compid != 65535; i++)
+               if (ver.manufacturer == vendor[i].compid) {
+                       ba2oui(&bdaddr, oui);
+                       comp = ouitocomp(oui);
+
+                       ba2str(&bdaddr, addr);
+                       printf("New BD address: %s", addr);
+
+                       if (comp) {
+                               printf(" (%s)\n\n", comp);
+                               free(comp);
+                       } else
+                               printf("\n\n");
+
+
+                       if (vendor[i].write_bd_addr(dd, &bdaddr) < 0) {
+                               fprintf(stderr, "Can't write new address\n");
+                               hci_close_dev(dd);
+                               return(1);
+                       }
+
+                       printf("Address changed\n");
+
+                       if (reset && vendor[i].reset_device) {
+                               if (vendor[i].reset_device(dd) < 0) {
+//                                     printf("Reset device manually\n");
+                               } else {
+                                       ioctl(dd, HCIDEVRESET, dev);
+                                       printf("Device reset successully\n");
+                               }
+                       } else {
+                               printf("Reset device now\n");
+                       }
+
+                       //ioctl(dd, HCIDEVRESET, dev);
+                       //ioctl(dd, HCIDEVDOWN, dev);
+                       //ioctl(dd, HCIDEVUP, dev);
+
+                       hci_close_dev(dd);
+                       return(0);
+               }
+
+       hci_close_dev(dd);
+
+       printf("\n");
+       fprintf(stderr, "Unsupported manufacturer\n");
+
+       return(1);
+}
diff --git a/btdev.h b/btdev.h
new file mode 100644 (file)
index 0000000..4809717
--- /dev/null
+++ b/btdev.h
@@ -0,0 +1,45 @@
+/* 
+   SpoofTooph
+   Copyright (C) 2010 Shadow Cave LLC
+
+   Written 2010 by JP Dunning (.ronin)
+   ronin@shadowcave.org
+   <www.hackfromacave.com>
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY 
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+   OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS 
+   DISCLAIMED.
+*/
+
+#define LENGTH_NAME    249
+#define LENGTH_ADDR    18
+#define LENGTH_CLASS   9
+
+struct btdev {
+
+
+char name[LENGTH_NAME];
+char addr[LENGTH_ADDR];
+char cod[LENGTH_CLASS];
+int flags;
+int major_class;
+int minor_class;
+uint8_t pscan_rep_mode;
+uint8_t pscan_mode;
+uint8_t clock_offset;
+
+
+};
diff --git a/dev_class.c b/dev_class.c
new file mode 100644 (file)
index 0000000..ec70ac9
--- /dev/null
@@ -0,0 +1,255 @@
+/* 
+   SpoofTooph
+   Copyright (C) 2010 Shadow Cave LLC
+
+   Written 2010 by JP Dunning (.ronin)
+   ronin [ at ] shadowcave [dt] org
+   <www.hackfromacave.com>
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY 
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+   OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS 
+   DISCLAIMED.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* 
+ * A majority of the following code is from 'hciconfig.c'
+ */
+static char * get_minor_device_name(int major, int minor)
+{
+       switch (major) {
+       case 0: /* misc */
+               return "";
+       case 1: /* computer */
+               switch(minor) {
+               case 0:
+                       return "Uncategorized";
+               case 1:
+                       return "Desktop workstation";
+               case 2:
+                       return "Server";
+               case 3:
+                       return "Laptop";
+               case 4:
+                       return "Handheld";
+               case 5:
+                       return "Palm";
+               case 6:
+                       return "Wearable";
+               }
+               break;
+       case 2: /* phone */
+               switch(minor) {
+               case 0:
+                       return "Uncategorized";
+               case 1:
+                       return "Cellular";
+               case 2:
+                       return "Cordless";
+               case 3:
+                       return "Smart phone";
+               case 4:
+                       return "Wired modem / voice gateway";
+               case 5:
+                       return "Common ISDN Access";
+               case 6:
+                       return "Sim Card Reader";
+               }
+               break;
+       case 3: /* lan access */
+               if (minor == 0)
+                       return "Uncategorized";
+               switch(minor / 8) {
+               case 0:
+                       return "Fully available";
+               case 1:
+                       return "1-17% utilized";
+               case 2:
+                       return "17-33% utilized";
+               case 3:
+                       return "33-50% utilized";
+               case 4:
+                       return "50-67% utilized";
+               case 5:
+                       return "67-83% utilized";
+               case 6:
+                       return "83-99% utilized";
+               case 7:
+                       return "No service available";
+               }
+               break;
+       case 4: /* audio/video */
+               switch(minor) {
+               case 0:
+                       return "Uncategorized";
+               case 1:
+                       return "Headset profile";
+               case 2:
+                       return "Hands-free";
+                       /* 3 is reserved */
+               case 4:
+                       return "Microphone";
+               case 5:
+                       return "Loudspeaker";
+               case 6:
+                       return "Headphones";
+               case 7:
+                       return "Portable Audio";
+               case 8:
+                       return "Car Audio";
+               case 9:
+                       return "Set-top box";
+               case 10:
+                       return "HiFi Audio Device";
+               case 11:
+                       return "VCR";
+               case 12:
+                       return "Video Camera";
+               case 13:
+                       return "Camcorder";
+               case 14:
+                       return "Video Monitor";
+               case 15:
+                       return "Video Display and Loudspeaker";
+               case 16:
+                       return "Video Conferencing";
+                       /* 17 is reserved */
+               case 18:
+                       return "Gaming/Toy";
+               }
+               break;
+       case 5: /* peripheral */ {
+               static char cls_str[48];
+               
+               cls_str[0] = '\0';
+
+               switch(minor & 48) {
+               case 16:
+                       strncpy(cls_str, "Keyboard", sizeof(cls_str));
+                       break;
+               case 32:
+                       strncpy(cls_str, "Pointing device", sizeof(cls_str));
+                       break;
+               case 48:
+                       strncpy(cls_str, "Combo keyboard/pointing device", sizeof(cls_str));
+                       break;
+               }
+               if((minor & 15) && (strlen(cls_str) > 0))
+                       strcat(cls_str, "/");
+
+               switch(minor & 15) {
+               case 0:
+                       break;
+               case 1:
+                       strncat(cls_str, "Joystick", sizeof(cls_str) - strlen(cls_str));
+                       break;
+               case 2:
+                       strncat(cls_str, "Gamepad", sizeof(cls_str) - strlen(cls_str));
+                       break;
+               case 3:
+                       strncat(cls_str, "Remote control", sizeof(cls_str) - strlen(cls_str));
+                       break;
+               case 4:
+                       strncat(cls_str, "Sensing device", sizeof(cls_str) - strlen(cls_str));
+                       break;
+               case 5:
+                       strncat(cls_str, "Digitizer tablet", sizeof(cls_str) - strlen(cls_str));
+                       break;
+               case 6:
+                       strncat(cls_str, "Card reader", sizeof(cls_str) - strlen(cls_str));
+                       break;
+               default:
+                       strncat(cls_str, "(reserved)", sizeof(cls_str) - strlen(cls_str));
+                       break;
+               }
+               if(strlen(cls_str) > 0)
+                       return cls_str;
+       }
+       case 6: /* imaging */
+               if (minor & 4)
+                       return "Display";
+               if (minor & 8)
+                       return "Camera";
+               if (minor & 16)
+                       return "Scanner";
+               if (minor & 32)
+                       return "Printer";
+               break;
+       case 7: /* wearable */
+               switch(minor) {
+               case 1:
+                       return "Wrist Watch";
+               case 2:
+                       return "Pager";
+               case 3:
+                       return "Jacket";
+               case 4:
+                       return "Helmet";
+               case 5:
+                       return "Glasses";
+               }
+               break;
+       case 8: /* toy */
+               switch(minor) {
+               case 1:
+                       return "Robot";
+               case 2:
+                       return "Vehicle";
+               case 3:
+                       return "Doll / Action Figure";
+               case 4:
+                       return "Controller";
+               case 5:
+                       return "Game";
+               }
+               break;
+       case 63:        /* uncategorised */
+               return "";
+       }
+       return "Unknown";
+}
+
+/* 
+ * major_devices[] from 'hciconfig.c'
+ *
+ */
+static const char *major_devices[] = { "Miscellaneous",
+                               "Computer",
+                               "Phone",
+                               "LAN Access",
+                               "Audio/Video",
+                               "Peripheral",
+                               "Imaging",
+                               "Wearable",
+                               "Toy",
+                               "Uncategorized" };
+                               
+/* 
+ * services[] from 'hciconfig.c'
+ *
+ */
+static const char *services[] = { "Positioning",
+                               "Networking",
+                               "Rendering",
+                               "Capturing",
+                               "Object Transfer",
+                               "Audio",
+                               "Telephony",
+                               "Information" };
\ No newline at end of file
diff --git a/makefile b/makefile
new file mode 100755 (executable)
index 0000000..4142789
--- /dev/null
+++ b/makefile
@@ -0,0 +1,21 @@
+# Makefile for spooftooph
+
+CC = gcc
+BT_LIB = -lbluetooth
+NCURSES_LIB = -lncurses
+PTHREAD = -pthread
+BIN = /usr/bin
+
+all: spooftooph
+
+spooftooph:
+       $(CC) $(BT_LIB) $(NCURSES_LIB) $(PTHREAD) dev_class.c namelist.c spooftooph.c bdaddr.c oui.c -o spooftooph
+
+install:
+       cp spooftooph $(BIN)
+
+uninstall:
+       rm -i $(BIN)/spooftooph
+
+clean:
+       rm spooftooph
diff --git a/namelist.c b/namelist.c
new file mode 100644 (file)
index 0000000..92266c6
--- /dev/null
@@ -0,0 +1,241 @@
+/* 
+   namelist.c
+   Copyright (C) 2010 Shadow Cave LLC
+
+   Written 2010 by JP Dunning (.ronin)
+   ronin [ at ] shadowcave [dt] org
+   <www.hackfromacave.com>
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY 
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+   OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS 
+   DISCLAIMED.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+static char * rand_name(int i) {
+
+  switch (i) {
+       case 0: return "Jacob";
+       case 1: return "Emma";
+       case 2: return "Michael";
+       case 3: return "Isabella";
+       case 4: return "Ethan";
+       case 5: return "Emily";
+       case 6: return "Joshua";
+       case 7: return "Madison";
+       case 8: return "Daniel";
+       case 9: return "Ava";
+       case 10: return "Alexander";
+       case 11: return "Olivia";
+       case 12: return "Anthony";
+       case 13: return "Sophia";
+       case 14: return "William";
+       case 15: return "Abigail";
+       case 16: return "Christopher";
+       case 17: return "Elizabeth";
+       case 18: return "Matthew";
+       case 19: return "Chloe";
+       case 20: return "Jayden";
+       case 21: return "Samantha";
+       case 22: return "Andrew";
+       case 23: return "Addison";
+       case 24: return "Joseph";
+       case 25: return "Natalie";
+       case 26: return "David";
+       case 27: return "Mia";
+       case 28: return "Noah";
+       case 29: return "Alexis";
+       case 30: return "Aiden";
+       case 31: return "Alyssa";
+       case 32: return "James";
+       case 33: return "Hannah";
+       case 34: return "Ryan";
+       case 35: return "Ashley";
+       case 36: return "Logan";
+       case 37: return "Ella";
+       case 38: return "John";
+       case 39: return "Sarah";
+       case 40: return "Nathan";
+       case 41: return "Grace";
+       case 42: return "Elijah";
+       case 43: return "Taylor";
+       case 44: return "Christian";
+       case 45: return "Brianna";
+       case 46: return "Gabriel";
+       case 47: return "Lily";
+       case 48: return "Benjamin";
+       case 49: return "Hailey";
+       case 50: return "Jonathan";
+       case 51: return "Anna";
+       case 52: return "Tyler";
+       case 53: return "Victoria";
+       case 54: return "Samuel";
+       case 55: return "Kayla";
+       case 56: return "Nicholas";
+       case 57: return "Lillian";
+       case 58: return "Gavin";
+       case 59: return "Lauren";
+       case 60: return "Dylan";
+       case 61: return "Kaylee";
+       case 62: return "Jackson";
+       case 63: return "Allison";
+       case 64: return "Brandon";
+       case 65: return "Savannah";
+       case 66: return "Caleb";
+       case 67: return "Nevaeh";
+       case 68: return "Mason";
+       case 69: return "Gabriella";
+       case 70: return "Angel";
+       case 71: return "Sofia";
+       case 72: return "Isaac";
+       case 73: return "Makayla";
+       case 74: return "Evan";
+       case 75: return "Avery";
+       case 76: return "Jack";
+       case 77: return "Riley";
+       case 78: return "Kevin";
+       case 79: return "Julia";
+       case 80: return "Jose";
+       case 81: return "Leah";
+       case 82: return "Isaiah";
+       case 83: return "Aubrey";
+       case 84: return "Luke";
+       case 85: return "Jasmine";
+       case 86: return "Landon";
+       case 87: return "Audrey";
+       case 88: return "Justin";
+       case 89: return "Katherine";
+       case 90: return "Lucas";
+       case 91: return "Morgan";
+       case 92: return "Zachary";
+       case 93: return "Brooklyn";
+       case 94: return "Jordan";
+       case 95: return "Destiny";
+       case 96: return "Robert";
+       case 97: return "Sydney";
+       case 98: return "Aaron";
+       case 99: return "Alexa";    
+    }
+}
+
+static char * scifi_name(int i) {
+
+  switch (i) {
+        case 0: return "Spock";                                              
+        case 1: return "Chekov";                                             
+        case 2: return "Starbuck";                                           
+        case 3: return "Jean-Luc Picard";                                    
+        case 4: return "Quark";                                              
+        case 5: return "Gandolf";                                            
+        case 6: return "Frodo Baggins";                                      
+        case 7: return "Hermione";                                           
+        case 8: return "Dr. Who";                                            
+        case 9: return "John Sheridan";                                      
+        case 10: return "Delenn";                                            
+        case 11: return "Samantha Carter";                                   
+        case 12: return "John Criton";                                       
+        case 13: return "Moya";                                              
+        case 14: return "G'Kar";                                             
+        case 15: return "Lee Adama";                                         
+        case 16: return "Spot";                                              
+        case 17: return "Lwaxana Troy";                                      
+        case 18: return "Reginald Barclay";                                  
+        case 19: return "Jadzia Dax";                                        
+        case 20: return "Kes";                                               
+        case 21: return "Zathras";                                           
+        case 22: return "Porkins";                                           
+        case 23: return "Alfred Bester";                                     
+        case 24: return "Walter Harriman";                                   
+        case 25: return "Selmak";                                            
+        case 26: return "Gort";                                              
+        case 27: return "Wedge";                                             
+        case 28: return "Greedo";                                            
+        case 29: return "Moya";                                              
+        case 30: return "Stark";                                             
+        case 31: return "Luna";                                              
+        case 32: return "Malcolm Reynolds";                                  
+        case 33: return "Jayne Cobb";                                        
+        case 34: return "Inara Serra";                                       
+        case 35: return "Boomer";                                            
+        case 36: return "Gaius Baltar";                                      
+        case 37: return "Saul Tigh";                                         
+        case 38: return "Laura Roslin";                                      
+        case 39: return "Lee Adama";                                         
+        case 40: return "Londo Mollari";                                     
+        case 41: return "Lennier";                                           
+        case 42: return "Jaime Sommers";                                     
+        case 43: return "Oscar Goldman";                                     
+        case 44: return "Steve Austin";                                      
+        case 45: return "Dr. Zachary Smith";                                 
+        case 46: return "Will Robinson";                                     
+        case 47: return "Penny Robinson";                                    
+        case 48: return "Tom Servo";                                         
+        case 49: return "Crow T. Robot";                                     
+        case 50: return "Walter Skinner";                                    
+        case 51: return "CGB Spender";                                       
+        case 52: return "Dana Scully";                                       
+        case 53: return "Fox Mulder";                                        
+        case 54: return "Rick Deckard";                                      
+        case 55: return "Sam Beckett";                                       
+        case 56: return "Al Calavicci";                                      
+        case 57: return "Eowyn";                                             
+        case 58: return "Elrond";                                            
+        case 59: return "Gandalf";                                           
+        case 60: return "Denethor";                                          
+        case 61: return "Olivia Dunham";                                     
+        case 62: return "Walter Bishop";                                     
+        case 63: return "Peter Bishop";
+        case 64: return "Joh Fredersen";
+        case 65: return "Neo";
+        case 66: return "Morpheus";
+        case 67: return "Akira";
+        case 68: return "Riddick";
+        case 69: return "Dr. Who";
+        case 70: return "Philip J. Fry";
+        case 71: return "Leela";
+        case 72: return "Bender Bending Rodríguez";
+        case 73: return "Zapp Brannigan";
+        case 74: return "Hubert J. Farnsworth";
+        case 75: return "Master / Blaster";
+        case 76: return "Thorn";
+        case 77: return "Snake Plissken";
+        case 78: return "Clu";
+        case 79: return "Tron";
+        case 80: return "Sark";
+        case 81: return "Sam Lowry";
+        case 82: return "Korben Dallas";
+        case 83: return "Zorg";
+        case 84: return "Leeloo";
+        case 85: return "Luke Skywalker";
+        case 86: return "Han Solo";
+        case 87: return "Princess Leia";
+        case 88: return "Darth Vader";
+        case 89: return "Obi-Wan Kenobi";
+        case 90: return "R2-D2";
+        case 91: return "Han Solo";
+        case 92: return "Yoda";
+        case 93: return "Chewbacca";
+        case 94: return "Lando Calrissian";
+        case 95: return "Saruman";
+        case 96: return "C-3PO";
+        case 97: return "Elrond";
+        case 98: return "Gollum";
+        case 99: return "Gimli";
+  }
+}
diff --git a/oui.c b/oui.c
new file mode 100644 (file)
index 0000000..1096d20
--- /dev/null
+++ b/oui.c
@@ -0,0 +1,109 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include "oui.h"
+
+/* http://standards.ieee.org/regauth/oui/oui.txt */
+
+#define OUIFILE "/var/lib/misc/oui.txt"
+
+char *ouitocomp(const char *oui)
+{
+       struct stat st;
+       char *str, *map, *off, *end;
+       int fd;
+
+       fd = open("oui.txt", O_RDONLY);
+       if (fd < 0) {
+               fd = open(OUIFILE, O_RDONLY);
+               if (fd < 0) {
+                       fd = open("/usr/share/misc/oui.txt", O_RDONLY);
+                       if (fd < 0)
+                               return NULL;
+               }
+       }
+
+       if (fstat(fd, &st) < 0) {
+               close(fd);
+               return NULL;
+       }
+
+       str = malloc(128);
+       if (!str) {
+               close(fd);
+               return NULL;
+       }
+
+       memset(str, 0, 128);
+
+       map = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+       if (!map || map == MAP_FAILED) {
+               free(str);
+               close(fd);
+               return NULL;
+       }
+
+       off = strstr(map, oui);
+       if (off) {
+               off += 18;
+               end = strpbrk(off, "\r\n");
+               strncpy(str, off, end - off);
+       } else {
+               free(str);
+               str = NULL;
+       }
+
+       munmap(map, st.st_size);
+
+       close(fd);
+
+       return str;
+}
+
+int oui2comp(const char *oui, char *comp, size_t size)
+{
+       char *tmp;
+
+       tmp = ouitocomp(oui);
+       if (!tmp)
+               return -1;
+
+       snprintf(comp, size, "%s", tmp);
+
+       free(tmp);
+
+       return 0;
+}
diff --git a/oui.h b/oui.h
new file mode 100644 (file)
index 0000000..ad66e56
--- /dev/null
+++ b/oui.h
@@ -0,0 +1,25 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+char *ouitocomp(const char *oui);
+int oui2comp(const char *oui, char *comp, size_t size);
diff --git a/spooftooph.c b/spooftooph.c
new file mode 100644 (file)
index 0000000..29e26cb
--- /dev/null
@@ -0,0 +1,1147 @@
+/* 
+   SpoofTooph
+   Copyright (C) 2009-2012 Shadow Cave LLC
+
+   Written 2009-2012 by JP Dunning (.ronin)
+   ronin [ at ] shadowcave [dt] org
+   <www.hackfromacave.com>
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY 
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+   OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS 
+   DISCLAIMED.
+*/
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <ncurses.h>
+#include <pthread.h>
+
+#include "bdaddr.c"
+#include "dev_class.c"
+#include "namelist.c"
+#include "btdev.h"
+
+typedef struct btdev btdev;
+
+// TESTING
+//
+// int thread_count = 0;
+//
+char * version = "0.5.2";
+
+int numaddrs = 0;              // Number if devices logged
+int max_addrs = 10;            // Maximum number of devices in array
+int thread_block = 0;          // Blocks running of thread
+
+int scifi_flag = 0;            // Indicates is SciFi names should be used
+int u_flag = 0;                        // Indicated a interactive delay for reinitializing interface
+int B_flag = 0;                        // Disable banner
+
+int num_list = 7;              // Number of devices per page
+int hdev = 0;
+char * log_file = NULL;                // Loge file
+void * run_thread();
+btdev * mydev;                 // Struct to store device infromation
+pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
+
+
+void onExit( void )
+{
+//    save_file();
+}
+
+// Resize mydev array
+int incrementArray()
+{
+       max_addrs += 10;
+       mydev = (btdev *)realloc(mydev, (max_addrs * sizeof(btdev)));
+
+       return 0;
+}
+
+// Verify the address is a valid Bluetooth address
+int check_addr(char opt[])
+{
+       // Checking for valid addr
+
+       int i = 0;
+       for (i; i < 17; i++)
+       {
+               if ((((int)opt[i] >= 48) && ((int)opt[i] <= 57)) || (((int)opt[i] >= 65) && ((int)opt[i] <= 70))) {}
+               else {
+                       fprintf(stderr, "Invalid addr: %s\n", opt);
+                       return(1);
+               }
+               i++;
+
+               if ((((int)opt[i] >= 48) && ((int)opt[i] <= 57)) || (((int)opt[i] >= 65) && ((int)opt[i] <= 70))) {}
+               else {
+                       fprintf(stderr, "Invalid addr: %s\n", opt);
+                       return(1);
+               }
+               i++;
+
+               if (((i == 17)&&((int)opt[i] == 0)) || ((int)opt[i] == 58)) {}
+               else {
+                       fprintf(stderr, "Invalid addr: %s\n", opt);
+                       return(1);
+               }
+       }
+       
+       return 0;
+}
+
+// Verify that the input is a valid class
+int check_class(char * opt)
+{      
+
+       // Checking for valid class
+       if ((opt[0] != '0') || (opt[1] != 'x')) {
+               fprintf(stderr,"Invalid class: %s\n", opt);
+               return(1);
+       }
+       int i = 2;
+       for (i; i < 7; i++)
+       {
+               if ((((int)opt[i] >= 48) && ((int)opt[i] <= 57)) || (((int)opt[i] >= 97) && ((int)opt[i] <= 122))) {}
+               else {
+                       fprintf(stderr,"Invalid class: %s\n", opt);
+                       return(1);
+               }
+       }
+       return 0;
+}
+
+/* 
+Write the device class.
+
+Most of the following function is form 'hciconfig.c' in BlueZ
+*/
+static int cmd_class(int hdev, char *opt)
+{
+       if (check_class(opt))
+               return 1;
+       
+       int s = hci_open_dev(hdev);
+       if (s < 0) {
+               fprintf(stderr,"Can't open device hci%d: %s (%d)\n",
+                                               hdev, strerror(errno), errno);
+               return(1);
+       }
+       if (opt) {
+               uint32_t cod = strtoul(opt, NULL, 16);
+               if (hci_write_class_of_dev(s, cod, 2000) < 0) {
+                       fprintf(stderr,"Can't write local class of device on hci%d: %s (%d)\n",
+                                               hdev, strerror(errno), errno);
+                       return(1);
+                }
+       }
+//     printf("Class Set: %s\n", opt);
+       return(0);
+}
+
+/* 
+Write the device name.
+
+Most of the following function is form 'hciconfig.c' in BlueZ
+*/
+static int cmd_name(int hdev, char *opt)
+{
+       if ((sizeof(opt) < 0) || (sizeof(opt) > 248)) {
+               fprintf(stderr,"error: Invalid name: %s\n", opt);
+               return(1);
+       }
+
+       int dd;
+
+       dd = hci_open_dev(hdev);
+       if (dd < 0) {
+               fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
+                                               hdev, strerror(errno), errno);
+               return(1);
+       }
+
+       if (opt) {
+               if (hci_write_local_name(dd, opt, 2000) < 0) {
+                       fprintf(stderr, "Can't change local name on hci%d: %s (%d)\n",
+                                               hdev, strerror(errno), errno);
+                       return(1);
+               }
+       } 
+       
+       hci_close_dev(dd);
+//     printw("Name Set:  %s\n", opt);
+       return(0);
+}
+
+// Convert hex into integer
+int hextoint(char hex)
+{
+       switch(hex)
+       {
+         case '0':
+               return 0;
+         case '1':
+               return 1;
+         case '2':
+               return 2;
+         case '3':
+               return 3;
+         case '4':
+               return 4;
+         case '5':
+               return 5;
+         case '6':
+               return 6;
+         case '7':
+               return 7;
+         case '8':
+               return 8;
+         case '9':
+               return 9;
+         case 'a':
+               return 10;
+         case 'b':
+               return 11;
+         case 'c':
+               return 12;
+         case 'd':
+               return 13;
+         case 'e':
+               return 14;
+         case 'f':
+               return 15;
+         case 'A':
+               return 10;
+         case 'B':
+               return 11;
+         case 'C':
+               return 12;
+         case 'D':
+               return 13;
+         case 'E':
+               return 14;
+         case 'F':
+               return 15;
+       }
+       
+       return -1;
+}
+
+int put_class(int dev_index, char * cod)
+{
+  
+
+       int i=2;
+       for (i=2; i < 8; i++) {
+               if (hextoint(cod[i]) == -1) {
+                       fprintf(stderr,"invalid class data.\n");
+                       return 1;
+               }
+       }
+
+       mydev[dev_index].flags = (hextoint(cod[2])*16)+(hextoint(cod[3]));
+       mydev[dev_index].major_class = (hextoint(cod[4])*16)+(hextoint(cod[5]));
+       mydev[dev_index].minor_class = (hextoint(cod[6])*16)+(hextoint(cod[7]));
+
+       return 0;
+}
+
+// Get the Class from the Flags, Major Class, and Minor Class
+int get_class(int dev_index, char * cod)
+{ 
+       cod[0] = '0';
+       cod[1] = 'x';
+       char class_part1[3] = {0};
+       char class_part2[3] = {0};
+       char class_part3[3] = {0}; 
+       int n1, n2, n3;
+       
+       n1 = sprintf(class_part1, "%02x", mydev[dev_index].flags);              // Get hex values of flag
+       cod[2] = class_part1[0];
+       cod[3] = class_part1[1];
+       n2 = sprintf(class_part2, "%02x", mydev[dev_index].major_class);        // Get hex values of major class
+       cod[4] = class_part2[0];
+       cod[5] = class_part2[1];
+       n3 = sprintf(class_part3, "%02x", mydev[dev_index].minor_class);        // Get hex values of minor class
+       cod[6] = class_part3[0];
+       cod[7] = class_part3[1];
+       
+       return (1);
+}
+
+// Make appropriate funtion calls to spoof the device
+int spoof(int dev_index, int hdev)
+{
+  
+       cmd_bdaddr(hdev, mydev[dev_index].addr);
+//     if (u_flag){
+//             printw("Press any key once USB is reinitialized");
+//             getchar();
+//     }
+
+       sleep(10);
+
+//     cmd_class(hdev, class);
+       cmd_class(hdev, mydev[dev_index].cod);
+       cmd_name(hdev, mydev[dev_index].name);
+       return 0;
+}
+
+/* 
+Write the print the services from the class.
+
+Most of the following function is form 'hciconfig.c' in BlueZ
+*/
+int print_service(int n)
+{
+       unsigned int i;
+       int first = 1;
+       printw("[");
+       for (i = 0; i < (sizeof(services) / sizeof(*services)); i++) {
+               if (mydev[n].flags & (1 << i)) {
+                       if (!first) {
+                               printw(",");
+                               printw(" %s", services[i]);
+                               first = 0;
+                       }
+                       else {
+                               first = 0;
+                               printw(" %s", services[i]);
+                       }
+               }
+       }
+       printw(" ]");
+
+       return 0;
+}
+// Display the major and minor class of device
+int print_class(int i)
+{
+       char * minor = get_minor_device_name(mydev[i].major_class, mydev[i].minor_class);
+                                       
+       if ((mydev[i].major_class & 0x1f) >= sizeof(major_devices) / sizeof(*major_devices))
+               printw("%-40s","Unknown");
+       else {
+               char classes[50];
+               strcpy(classes, major_devices[mydev[i].major_class & 0x1f]);
+               strcat(classes, " (");
+               strcat(classes,get_minor_device_name(mydev[i].major_class & 0x1f, mydev[i].minor_class));
+               strcat(classes, ")");
+               printw("%-40s", classes);
+       }
+       return 0;
+}
+
+// Print a list of devices
+int choice_list(int page)
+{
+       // Get current time
+       time_t rawtime;
+       struct tm * timeinfo;
+       time (&rawtime);
+       timeinfo = localtime (&rawtime);
+       
+       clear();
+
+       if (!B_flag) {
+       // Print to screen
+               printw("             _____                    __ _______                _     \n");
+               printw("            / ____|                  / _|__   __|              | |    \n");
+               printw("           | (___  _ __   ___   ___ | |_   | | ___   ___  _ __ | |__  \n");
+               printw("            \\___ \\| '_ \\ / _ \\ / _ \\|  _|  | |/ _ \\ / _ \\| '_ \\| '_ \\ \n");
+               printw("            ____) | |_) | (_) | (_) | |    | | (_) | (_) | |_) | | | |\n");
+               printw("           |_____/| .__/ \\___/ \\___/|_|    |_|\\___/ \\___/| .__/|_| |_|\n");
+               printw("                  | |                                    | |          \n");
+               printw("                  |_|                                    |_|          \n");
+       } else {
+               printw("\n                        SpoofTooph\n");                 
+       }
+       printw("\n                        Time: %s\n", asctime (timeinfo));
+       printw("   TYPE\t\t\t\t\t   NAME\n");
+       printw("   ADDR\t\t\tCLASS\t\t   SERVICES\n\n");
+
+       int i=page*num_list;    // Start index of device to print 
+       int n;                  // End index of device to print
+       
+       if ((i+num_list) > numaddrs) {
+               n = numaddrs;
+       } else {
+               n = i+num_list;
+       }
+       
+       // Print device info
+       while(i < n)
+       {
+         printw("%i) ",i );
+
+         print_class(i);
+         if (mydev[i].name)
+               printw("%s",mydev[i].name );
+         else
+               printw("%s", "Unknown");
+         printw("\n");
+         
+         printw("   %-21s0x%02x%02x%02x\t   " ,mydev[i].addr,mydev[i].flags, mydev[i].major_class, mydev[i].minor_class );
+//       printw("   %-21s%s\t   " ,mydev[i].addr,mydev[i].cod );
+
+         if(mydev[i].flags) {
+               print_service(i);
+         } else {
+               printw("%s", "Unspecified");
+         }
+         
+         printw("\n");
+         i++;
+       }
+
+       printw("\nPage %i of %i\n", (page + 1), ((numaddrs-1)/num_list + 1));
+       printw("\n's' make selection, 'p' previous page, 'n' next page, 'q' quite: ");
+
+       
+//     printw("Number of scans: %i", thread_count);
+       return 0;
+
+}
+
+// Assign random info to the Bluetooth interface
+int dev_random(int hdev)
+{
+       srand ( time(NULL) );
+       int major = (rand() % 9);
+
+       int minor = (rand() % 6);  // Add more robust verion later
+       
+       // Randomly add service flags
+       int flag = 0;              
+       if (rand() % 2) flag += 1;
+       if (rand() % 2) flag += 2;
+       if (rand() % 2) flag += 4;
+       if (rand() % 2) flag += 8;
+       if (rand() % 2) flag += 10;
+       if (rand() % 2) flag += 20;
+       if (rand() % 2) flag += 40;
+       if (rand() % 2) flag += 80;
+
+       // Generate random name
+       int name_choice = (rand() % 100);
+       char dev_name[100] = {0};
+
+       if (scifi_flag)
+               strcpy(dev_name, scifi_name(name_choice));
+       else
+               strcpy(dev_name, rand_name(name_choice));
+
+       strcat(dev_name, "\'s ");
+       strcat(dev_name, major_devices[major & 0x1f]);
+
+
+       // Generale Random Class
+       char class[9] = {0};
+       sprintf(class, "0x%02x%02x%02x", flag, major, minor);
+       char * class_str = class;
+       
+       // Generate random address
+       char addr_part[3] = {0};
+       char addr[18] = {0};
+       int i = 0;
+       addr[i++] = '0';
+       addr[i++] = '0';
+       addr[i++] = ':';
+       
+       while ( i < 18)
+       {
+               sprintf(addr_part, "%02x", (rand() % 254));     
+               addr[i++] = addr_part[0];
+               addr[i++] = addr_part[1];
+               addr[i++] = ':';
+       }
+
+       sprintf(addr_part, "%02x", (rand() % 254));     
+       addr[i++] = addr_part[0];
+       addr[i++] = addr_part[1];
+       
+       // Set Bluetooth info
+       
+       cmd_bdaddr(hdev, addr);
+       sleep(10);
+
+       cmd_class(hdev, class_str);
+       cmd_name(hdev, dev_name);
+}
+
+// Get devices from log file
+int load_log(char * log_file)
+{
+       FILE *file = fopen ( log_file, "r" );
+
+       if ( file != NULL ) {
+               
+               char line[LENGTH_NAME + LENGTH_ADDR + LENGTH_CLASS] = { 0 };
+               
+               // Read line by line
+               while (fgets( line, sizeof(line), file )) { 
+
+                       if (strcmp(line,"\n") != 0) {
+
+                               char * pound_index;
+                               
+                               // '#' indicates a line is commented out
+                               pound_index = strchr(line, '#');
+                               
+                               if (pound_index == NULL) {
+                                       
+                                       char name [LENGTH_NAME] = { 0 };
+                                       char addr [LENGTH_ADDR] = { 0 };
+                                       char class [LENGTH_CLASS] = { 0 };
+                                       char * add_addr;
+                                       add_addr = strchr(line, '\n');
+                                                                               
+                                       // Parse line for ADDR, CLASS, and NAME
+                                       sscanf(line, "%[^','],%[^','],%s", addr, class, name);
+                                       
+                                       // Add Name
+                                       strcpy(mydev[numaddrs].name, name);     
+                                       
+                                       // Add Addr
+                                       if (check_addr(addr) == 0) {
+                                               strcpy(mydev[numaddrs].addr, addr);     
+                                       } else {
+                                               fprintf(stderr,"Invalid or improper data from file.\n" ); 
+                                               return 1;
+                                       }
+                                       
+                                       // Add Class
+                                       if (check_class(class) == 0) {
+                                               put_class(numaddrs, class);
+                                       } else {
+                                               fprintf(stderr,"Invalid or improper data from file.\n" ); 
+                                               return 1;
+                                       }
+                                       
+                                       numaddrs++;     // Increment number of devs
+                               }
+                       }
+               }
+               fclose ( file );
+       }
+       else {  
+               fprintf(stderr,"File not found\n" ); 
+       }
+
+}
+
+
+int save_file()
+{
+       FILE *fp;
+       time_t rawtime;
+       struct tm * timeinfo;
+       int i = 0;
+       
+       if(numaddrs >= 1) {
+         
+               // Create file
+               if((fp = fopen(log_file, "w")) == NULL)
+                       return 1;
+
+               fprintf(fp, "%s,%s,%s\n", mydev[i].addr, mydev[i].cod, mydev[i].name);
+               fclose(fp);
+               i++;
+       }
+       
+       
+       while(i < numaddrs) {
+               // Append file
+               if((fp = fopen(log_file, "a")) == NULL)
+                       return 1;
+
+               fprintf(fp, "%s,%s,%s\n", mydev[i].addr, mydev[i].cod, mydev[i].name);
+               i++;
+               
+               fclose(fp);
+       }
+       
+       return 0;
+}
+
+
+// Scan for available bluetooth devices
+int scan(char * log_file)
+{
+       inquiry_info *ii = NULL;
+       int max_rsp, num_rsp;
+       int dev_id, sock, len, flags;
+       int i;
+       int t_count;
+       char addr[18] = { 0 };
+       
+//     dev_id = hci_get_route(NULL);
+       dev_id = hdev;
+       sock = hci_open_dev( dev_id );
+
+       // Error with opening socket
+       if (dev_id < 0 || sock < 0) {
+               fprintf(stderr,"error: opening socket\n");
+               close( sock );
+               return 1;
+       }
+       
+       len  = 3; //8;
+       max_rsp = 255;
+       flags = IREQ_CACHE_FLUSH;
+       ii = (inquiry_info*)malloc(max_rsp * sizeof(inquiry_info));
+       num_rsp = hci_inquiry(dev_id, len, max_rsp, NULL, &ii, flags);
+
+       // Check for any devices found
+       if( num_rsp < 0 ) {
+               close( sock );
+               return 1;
+       }
+       
+       // Cycle through all the addresses found
+       for (i = 0; i < num_rsp; i++) {
+
+               char name[248] = { 0 };
+               ba2str(&(ii+i)->bdaddr, addr);
+               memset(name, 0, sizeof(name));
+
+//             // Check for device name
+//             if (hci_read_remote_name(sock, &(ii+i)->bdaddr, sizeof(name), name, 0) < 0)
+//                     strcpy(name, "[unknown]");
+               
+               int num = 0;
+               int matchfound = 0;
+
+               // Check to see if a new device has been discovered
+               while (num < numaddrs) { 
+                       if (strcmp (addr, mydev[num].addr) == 0) { 
+                               matchfound = 1;
+                     
+                               // If the name of the device is found, replace "[unknown]" with the name.
+//                             if((strcmp(mydev[num].name, "[unknown]") == 0)&&(strcmp(name,"[unknown]") != 0)) {
+                               if(strcmp(mydev[num].name, "[unknown]") == 0) {
+                                       // Check for device name
+                                       if (hci_read_remote_name(sock, &(ii+i)->bdaddr, sizeof(name), name, 0) < 0)
+                                               strcpy(name, "[unknown]");
+       
+                                       strcpy(mydev[num].name, name);
+                               }
+                       }
+                       num++;
+               }
+
+               // Add newly found device to list
+               if (matchfound == 0) {
+                       
+                       if ((numaddrs+10) > max_addrs)
+                               incrementArray();
+
+                       // Check for device name
+                       if (hci_read_remote_name(sock, &(ii+i)->bdaddr, sizeof(name), name, 0) < 0)
+                               strcpy(name, "[unknown]");
+
+                       strcpy(mydev[numaddrs].addr, addr);
+                       strcpy(mydev[numaddrs].name, name);
+                       mydev[numaddrs].major_class = (ii+i)->dev_class[1];
+                       mydev[numaddrs].minor_class = (ii+i)->dev_class[0];
+                       mydev[numaddrs].pscan_rep_mode = (ii+i)->pscan_rep_mode;
+                       mydev[numaddrs].pscan_mode = (ii+i)->pscan_mode;
+                       mydev[numaddrs].clock_offset = (ii+i)->clock_offset;
+                       mydev[numaddrs].flags = (ii+i)->dev_class[2];
+                       sprintf(mydev[numaddrs].cod,"0x%02x%02x%02x",mydev[numaddrs].flags, mydev[numaddrs].major_class, mydev[numaddrs].minor_class);
+
+
+                       // Write to log file
+                       if (log_file) {
+                               
+                               FILE *fp;
+
+                               // Create file
+                               if((fp = fopen(log_file, "a")) == NULL) {
+                                       close( sock );
+                                       return 1;
+                               }
+
+                               time_t rawtime;
+                               struct tm * timeinfo;
+                               time (&rawtime);
+                               timeinfo = localtime (&rawtime);
+
+//                             fprintf(fp, "# DEVICE DISCOVERED: %s", asctime (timeinfo));
+//                             fprintf(fp, "%s\n%s\n0x%02x%02x%02x\n", name, addr, mydev[numaddrs].flags, mydev[numaddrs].major_class, mydev[numaddrs].minor_class);
+                               fprintf(fp, "%s,%s,%s\n", mydev[i].addr, mydev[i].cod, mydev[i].name);
+
+                               fclose (fp);
+                       }
+
+                       numaddrs++;
+               }
+       }
+
+       free( ii );
+       close( sock );
+       return 0;
+
+}
+
+// Used for thread to scan for Bluetooth devices
+void *run_thread()
+{
+       pthread_mutex_lock( &mutex1 );
+       
+       scan(log_file);
+       
+       pthread_mutex_unlock( &mutex1 );
+
+       thread_block = 2;
+}
+
+// Print help
+void usage()
+{
+       printf("\nspooftooph v%s by JP Dunning (.ronin) \n<www.hackfromacave.com>\n(c) 2009-2012 Shadow Cave LLC.\n\n"\
+                       "NAME\n\tspooftooph\n"\
+                       "\nSYNOPSIS\n\tspooftooph -i dev [-mstu] [-nac]|[-R]|[-r file] [-w file]\n"\
+                       "\nDESCRIPTION\n"\
+                       "\t-a <address>\t: Specify new BD_ADDR\n"\
+                       "\t-b <num_lines>\t: Number of Bluetooth profiles to display per page\n"\
+                       "\t-B \t\t: Disable banner for smaller screens (like phones)\n"\
+                       "\t-c <class>\t: Specify new CLASS\n"\
+                       "\t-h\t\t: Help\n"\
+                       "\t-i <dev>\t: Specify interface\n"\
+                       "\t-m\t\t: Specify multiple interfaces during selection\n"\
+                       "\t-n <name>\t: Specify new NAME\n"\
+                       "\t-r <file>\t: Read in CSV logfile\n"\
+                       "\t-R\t\t: Assign random NAME, CLASS, and ADDR\n"\
+                       "\t-s\t\t: Scan for devices in local area\n"\
+                       "\t-t <time>\t: Time interval to clone device in range\n"\
+                       "\t-u\t\t: USB delay.  Interactive delay for reinitializing interface\n"\
+                       "\t-w <file>\t: Write to CSV logfile\n"\
+                       "\t\t\t  (Useful in Virtualized environment when USB must be passed through.)\n\n", version);
+}
+
+int main(int argc, char **argv)
+{
+       atexit(onExit);
+
+       mydev = (btdev *)malloc(max_addrs * sizeof(btdev));
+
+       int dd = hci_open_dev(hdev);
+       char addr[18] = {0};
+//     char * name = NULL;
+       char name[300] = {0};
+       char * class = NULL;
+       
+       int manual = 0;
+       int scaning = 0;
+       int load = 0;
+       int i = 1;
+       int change_addr = 0;
+       int scan_iterations = 10;
+       int rand = 0;
+       int time_delay = 0;
+       int timeing = 0;
+       int mitm = 0;
+       
+       if (argc == 1) {
+               usage();
+               exit(1);
+       }
+
+       // Check arguments
+       while (i < argc) {              
+               if (strcmp(argv[i], "-h") == 0) {
+                       usage();
+                       return 0;
+               } else if (strcmp(argv[i], "-s") == 0) {
+                       scaning = 1;
+//             } else if (strcmp(argv[i], "-r") == 0) {
+//                     rand = 1;
+               } else if (strcmp(argv[i], "-R") == 0) {
+                       rand = 1;
+//                     scifi_flag=1;
+               } else if (strcmp(argv[i], "-u") == 0) {
+//                     rand = 1;
+                       u_flag=1;
+               } else if (strcmp(argv[i], "-B") == 0) {
+//                     rand = 1;
+                       B_flag=1;
+               } else if (strcmp(argv[i], "-t") == 0) {
+                       timeing = 1;
+                       if (++i < argc)
+                               time_delay = atoi(argv[i]);
+               } else if (strcmp(argv[i], "-i") == 0) {
+                       if (++i < argc)
+                               hdev = atoi(argv[i] + 3);
+               } else if (strcmp(argv[i], "-b") == 0) {
+                       if (++i < argc)
+                               num_list = atoi(argv[i]);
+                       if ((num_list > 100) || (num_list < 1)) {
+                               usage();
+                               return 1;
+                       }
+               } else if ((strcmp(argv[i], "-d") == 0) || (strcmp(argv[i], "-w") == 0)) {
+                       if (++i < argc)
+                               log_file = argv[i];
+               } else if ((strcmp(argv[i], "-l") == 0) || (strcmp(argv[i], "-r") == 0)){
+                       if (++i < argc)
+                               log_file = argv[i];
+                       load = 1;
+               } else if (strcmp(argv[i], "-n") == 0) {
+                       if (++i < argc)
+                               strcpy(name,argv[i]);
+                       manual=1;
+               } else if (strcmp(argv[i], "-m") == 0) {
+                       mitm=1;
+               } else if (strcmp(argv[i], "-c") == 0) {
+                       if (++i < argc){
+                               class = argv[i];}
+                       manual=1;
+               } else if (strcmp(argv[i], "-a") == 0) {
+                       if (++i < argc)
+                               strcpy(addr, argv[i]);
+                       change_addr=1;
+                       manual=1;
+               } else {
+                       usage();
+                       exit(1);
+               }
+               i++;
+       }
+
+       if ((manual + scaning + rand + load + timeing) != 1)
+       {
+               usage();
+               exit(1);
+       } else if (rand) {      // Generate random Bluetooth device info
+               dev_random(hdev);
+       } else if (manual) {    // Change Bluetooth device info to user specified input
+               if (change_addr) {
+                       if (cmd_bdaddr(hdev, addr))
+                               exit(1);
+               }
+               
+               if (u_flag){
+                       printf("Press any key once USB is reinitialized ");
+                       fflush(stdout);
+                       getchar();
+               } else 
+               {
+                       sleep(10);
+               }
+               
+               if (class) {                    
+                       if (cmd_class(hdev, class))
+                               exit(1);
+               } 
+               
+               if (name) {
+                       if (cmd_name(hdev, name))
+                               exit(1);
+               } 
+       } else if (load) {      // Read in devices from log file
+               mydev = (btdev *)malloc(sizeof(btdev)*100);
+
+               if ( load_log(log_file) != 0) {
+                     exit(1);
+               }
+
+               
+               initscr();
+               cbreak();
+               keypad(stdscr, TRUE);
+               noecho();
+               
+
+               int page = 0;
+               char ch = 'a';
+               char string_choice[3];          
+               int choice = -1;
+
+               do {
+
+                       choice_list(page);
+                       
+                       refresh();
+
+                       choice = (ch - 48);
+                       
+                       
+                       switch(ch)
+                       {       
+                         case 's':     // Make selection
+
+                               choice_list(page);
+                               timeout(100000);
+                               echo();
+                               
+                               if (mitm) {
+                                       char hcidev[6] = {0};
+
+                                       printw("\n\nProvide interface and hit ENTER (Ctrl+C to quite): ");
+//                                     refresh();
+                                       getnstr(hcidev, 6);
+                                       timeout(100000);                
+                                       hdev = atoi(hcidev + 3);
+
+                                       printw("\n\nMake selection by reference number and hit ENTER (Ctrl+C to quite): ");
+//                                     refresh();
+                                       getnstr(string_choice, 3);
+                                       timeout(100000);                
+                                       choice = atoi(string_choice);
+
+                                       if((choice >= 0) && (choice < numaddrs))
+                                       {
+                                               clear();
+                                               endwin();
+
+                                               fflush(stdout);
+                                               printf("\nCloning ...\n\n");
+                                               fflush(stdout);
+
+                                               spoof(choice, hdev);
+                                               timeout(100000);        
+                                               
+                                               initscr();
+                                               noecho();
+                                               timeout(100);
+//                                             refresh();
+                                               
+//                                             exit(0);
+                                       }
+                               } else {
+                                       printw("\n\nMake selection by reference number and hit ENTER (Ctrl+C to quite): ");
+                                       refresh();
+                                       getnstr(string_choice, 3);
+//                                             timeout(100);           
+                                       choice = atoi(string_choice);
+
+                                       if((choice >= 0) && (choice < numaddrs))
+                                       {
+                                               clear();
+                                               endwin();
+
+//                                             printw("\nCloning ...\n\n");
+                                               fflush(stdout);
+
+                                               printf("\nCloning ...\n\n");
+                                               fflush(stdout);
+                                               
+                                               spoof(choice, hdev);
+                                               
+                                               exit(0);
+                                       }
+                               }
+                         case 'n':     // Next page
+                                       if (((page+1)*num_list) < numaddrs) {
+                                               page++;
+                                               choice_list(page);
+                                       }
+                                       break;
+                         case 'p':     // Previous page
+                                       if (0 <= (page - 1)) {
+                                               page--;
+                                               choice_list(page);
+                                       }
+                                       break;
+                       }
+               } while(((ch = getch()) != 'Q') && (ch != 'q'));
+               
+               endwin();
+
+       } else if (timeing) {   // Scan for devices in range and clone info at specific intervals
+               
+               mydev = (btdev *)malloc(sizeof(btdev)*100);
+               
+               while(1)
+               {
+                       numaddrs = 0;
+                       scan(NULL);
+
+                       if (numaddrs >= 0)
+                       {
+                               spoof(0, hdev);
+                       } else {
+                               printf("\nNo change.\n");  // No device in range to clone
+                       }
+
+                       sleep(time_delay);
+               }
+       } else if (scaning) {   // Scan for devices in range and allow user to select the device info to clone 
+
+               mydev = (btdev *)malloc(sizeof(btdev)*100);
+
+               initscr();
+               cbreak();
+               keypad(stdscr, TRUE);
+               noecho();
+               timeout(100);
+               
+               int ch;
+
+               char string_choice[3];
+               
+               int choice = -1;
+               int rc;
+               pthread_t thread;
+               int page = 0;
+               
+               while(((ch = getch()) != 'Q') && (ch != 'q')) 
+               {
+                       if (thread_block == 0)
+                       {
+
+                               choice_list(page);
+                               refresh();
+
+                               thread_block = 1;
+
+//                             thread_count++;
+                               
+                               if(log_file) {
+                                       if (save_file() == 1) {
+                                               printf("File IO error\n\n");
+                                               exit(1);
+                                       }
+                               }
+
+                               // Create independent threads for scanning. Each of which will execute function
+                               if( (rc=pthread_create( &thread, NULL, &run_thread, NULL)) )
+                               {
+                                   endwin();
+                                   thread_block=0;
+                                   fprintf(stderr,"Thread creation failed: %d\n", rc);
+                                   exit (1);
+                               }                               
+                       } 
+                       
+                       if (thread_block == 2) {
+                               pthread_join(thread, NULL);
+                               thread_block = 0;
+                       }
+                       
+                       switch(ch)
+                       {       
+                               case 's':       // Make selection
+                                       if(log_file)
+                                               save_file();
+
+                                       choice_list(page);
+                                       timeout(100000);
+                                       echo();
+                                       
+                                       if (mitm) {
+                                               char hcidev[6] = {0};
+
+                                               printw("\n\nProvide interface and hit ENTER (Ctrl+C to quite): ");
+//                                             refresh();
+                                               getnstr(hcidev, 6);
+                                               timeout(100000);                
+                                               hdev = atoi(hcidev + 3);
+
+                                               printw("\n\nMake selection by reference number and hit ENTER (Ctrl+C to quite): ");
+//                                             refresh();
+                                               getnstr(string_choice, 3);
+                                               timeout(100000);                
+                                               choice = atoi(string_choice);
+
+                                               if((choice >= 0) && (choice < numaddrs))
+                                               {
+                                                       clear();
+                                                       endwin();
+
+                                                       fflush(stdout);
+                                                       printf("\nCloning ...\n\n");
+                                                       fflush(stdout);
+
+                                                       spoof(choice, hdev);
+                                                       timeout(100000);        
+                                                       
+                                                       initscr();
+                                                       noecho();
+                                                       timeout(100);
+//                                                     refresh();
+                                                       
+//                                                     exit(0);
+                                               }
+                                       } else {
+                                               printw("\n\nMake selection by reference number and hit ENTER (Ctrl+C to quite): ");
+                                               refresh();
+                                               getnstr(string_choice, 3);
+//                                             timeout(100);           
+                                               choice = atoi(string_choice);
+
+                                               if((choice >= 0) && (choice < numaddrs))
+                                               {
+                                                       clear();
+                                                       endwin();
+
+                                                       fflush(stdout);
+                                                       printf("\nCloning ...\n\n");
+                                                       fflush(stdout);
+
+                                                       spoof(choice, hdev);
+                                                       
+                                                       exit(0);
+                                               }
+                                       }
+                               case 'n':       // Next page
+//                                     if(log_file)
+//                                             save_file();
+
+                                       if (((page+1)*num_list) < numaddrs) {
+                                               page++;
+                                               choice_list(page);
+                                       }
+                                       break;
+                               case 'p':       // Previous page
+//                                     if(log_file)
+//                                             save_file();
+
+                                       if (0 <= (page - 1)) {
+                                               page--;
+                                               choice_list(page);
+                                       }
+                                       break;                                  
+                       }                       
+               }
+
+               if(log_file) {
+                       if (save_file() == 1) {
+                               printf("File IO error\n\n");
+                               exit(1);
+                       }
+               }
+               
+               pthread_cancel(thread);         
+               endwin();
+       } else
+       {
+               usage();
+       }
+       exit(0);
+}