/* zodiac - advanced dns spoofer * * sniffing functions * * by scut, smiler * */ #include #include #include #include #include #include #include #include #include #include "common.h" #include "packet.h" #include "sniff.h" extern struct in_addr localip; /* sniff_new * * the only function that should be called from outside. set up sniffing * device, create a new thread, then return. * open `interface' device for sniffing, tell sniffing thread to use * `pq_size' packet queues, available through `pq_list'. * store thread id of new thread in `tid'. * * return 0 if thread creation was successful * return 1 if thread creation failed */ int sniff_new (pthread_t *tid, char *interface, pq_thread *pq_thd) { int n; /* temporary return value */ sniff_info *sinfo; /* sniff information structure */ sinfo = xcalloc (1, sizeof (sniff_info)); /* open interface */ sinfo->device = sniff_open (interface); if (sinfo->device == NULL) { free (sinfo); return (1); } else if (sinfo->device->error == 1) { return (1); } if (sniff_dev_ip (interface, &localip) != 0) { free (sinfo); return (1); } /* store information into sinfo */ sinfo->pq_thd = pq_thd; /* and create our neat thread :) */ n = pthread_create (tid, NULL, (void *) sniff_handle, (void *) sinfo); if (n == -1) { sniff_dev_free (sinfo->device); free (sinfo); return (1); } /* successfully created sniffer thread */ return (0); } /* sniff_handle * * the main sniffing thread, fetching packets from the device, then calling * the packet grinder `pq_grind' to process the packets * * should never return except on error or program exit */ void * sniff_handle (sniff_info *sinfo) { int n; /* temporary return value */ pcap_handler grinder; /* pcap handler for the packet grinding function */ fprintf (stderr, "[855] hello world from sniffing thread\n"); /* sniff packets forever, until an error appears. pass incoming packets * to `pq_grind'. */ grinder = (pcap_handler) pq_grind; /* loop packets to pq_grind until error, passing sinfo struct for queueing */ n = pcap_loop (sinfo->device->pd, -1, grinder, (void *) sinfo); /* on error print error message, then free the device and terminate the * thread */ if (n == -1) { fprintf (stderr, "[855] sniff_handle (pcap_loop): %s\n", pcap_geterr (sinfo->device->pd)); } return (NULL); } /* sniff_filter * * install a filter `filter' on device `device', with netmask `netmask' * * return 0 on success * return 1 on failure */ int sniff_filter (s_dev *device, char *filter, bpf_u_int32 netmask) { int n; /* temporary return value */ struct bpf_program fprog; /* berkeley packet filter program structure */ n = pcap_compile (device->pd, &fprog, filter, 1, netmask); if (n == -1) { fprintf (stderr, "[855] sniff_filter (pcap_compile): " "failed to compile bpf program\n"); return (1); } n = pcap_setfilter (device->pd, &fprog); if (n == -1) { fprintf (stderr, "[855] sniff_filter (pcap_setfilter): " "failed to set bpf on %s\n", device->interface); return (1); } return (0); } /* sniff_open * * open `dev' for sniffing, or just the first sniffable one, if * dev is NULL. * * return NULL on failure * return pointer sniffing device structure on success * -smiler * Added link layer header length detection. */ s_dev * sniff_open (char *devname) { int n; /* temporary return value */ s_dev * device; /* sniffing device structure to create */ char errorbuf[PCAP_ERRBUF_SIZE]; /* error buffer for pcap message */ /* create new sniffing device structure in s_dev */ device = xcalloc (1, sizeof (s_dev)); /* check wether to use the first device or a specified device */ if (devname == NULL) { /* due to lame pcap manpage, you should not know that it's static *doh* */ device->interface = pcap_lookupdev (errorbuf); if (device->interface == NULL) { fprintf (stderr, "[855] sniff_open (pcap_lookupdev): %s\n", errorbuf); device->error = 1; return (device); } } else { /* if the interface we have to use is already known just copy it */ device->interface = xstrdup (devname); } /* try to open the device found */ device->pd = sniff_pcap_open (device->interface); if (device->pd == NULL) { device->error = 1; return (device); } /* now query some information about the device and store them into our struct */ n = pcap_lookupnet (device->interface, &device->localnet, &device->netmask, errorbuf); if (n == -1) { device->error = 1; return (device); } device->linktype = pcap_datalink (device->pd); if (device->linktype == -1) { device->error = 1; return (device); } switch (device->linktype) { /* not sure about all of these, but they work for me :\ -z */ case DLT_SLIP: case DLT_PPP: case DLT_NULL: device->linkhdrlen = 4; break; case DLT_RAW: device->linkhdrlen = 0; break; case DLT_EN10MB: default: device->linkhdrlen = 14; break; } fprintf (stderr, "[855] sniff_open: linkhdrlen = %ld\n", device->linkhdrlen); /* thx random for figuring this putty ;) */ sniff_filter (device, "", device->netmask); return (device); } /* sniff_pcap_open * * securely wraps the pcap_open_live call to catch any errors * * return NULL on failure * return capture descriptor on succes */ pcap_t * sniff_pcap_open (char *device) { char errorbuf[PCAP_ERRBUF_SIZE]; /* error buffer */ pcap_t * pdes = NULL; /* packet capture descriptor */ pdes = pcap_open_live (device, SNAPLEN, /*PROMISC*/ 0, READ_TIMEOUT, errorbuf); if (pdes == NULL) { fprintf (stderr, "[855] sniff_pcap_open (pcap_open_live): %s\n", errorbuf); return (NULL); } return (pdes); } /* sniff_dev_free * * close and free a sniffing device */ void sniff_dev_free (s_dev *device) { pcap_close (device->pd); if (device->interface) free (device->interface); free (device); return; } /* sniff_dev_ip * * get the ip given the name of a device. * i /hope/ this is portable ;) * -smiler 991001 * * return 0 on success * return -1 on failure */ int sniff_dev_ip (const char *dev, struct in_addr *ip) { int ifsock, i_cnt; struct ifconf ifc; struct ifreq *ifr; char buf[1024]; ifsock = socket (AF_INET, SOCK_DGRAM, 0); if (ifsock < 0) return (-1); ifc.ifc_len = sizeof (buf); ifc.ifc_buf = buf; if (ioctl (ifsock, SIOCGIFCONF, &ifc) < 0) return (-1); i_cnt = ifc.ifc_len / sizeof(struct ifreq); for (ifr = ifc.ifc_req; i_cnt ; i_cnt--, ifr++) { if (strcmp (dev, ifr->ifr_name) == 0) { memcpy (ip, &((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr, sizeof (struct in_addr)); return (0); } } return (-1); }