#include "arp.h" Arp::Arp() { terminated = true; device = NULL; errbuf = new char[PCAP_ERRBUF_SIZE]; } Arp::~Arp() { stop(); delete [] errbuf; } QStringList Arp::getDeviceList() { QStringList list; pcap_if_t *alldevs = NULL; pcap_if_t *dev = NULL; if (pcap_findalldevs(&alldevs, errbuf) == -1) { fprintf(stderr, "Couldn't find any device: %s\n", errbuf); return list; } /* add devices to the list */ for(dev=alldevs; dev; dev=dev->next) { list << QString(dev->name); } pcap_freealldevs(alldevs); return list; } QString Arp::lastError() { return QString(errbuf); } bool Arp::start(QString device) { char* deviceptr = NULL; char filter_exp[] = "arp"; this->stop(); /* if device is empty, selects default device */ if (device.isEmpty()) { deviceptr = pcap_lookupdev(errbuf); if (deviceptr == NULL) { fprintf(stderr, "Couldn't find default device: %s\n", errbuf); return false; } device = QString(QLatin1String(deviceptr)); } /* Converts QString device to char* */ QByteArray ba = device.toLatin1(); deviceptr = ba.data(); this->device = new char[ba.length() + 1]; strcpy(this->device, deviceptr); /* fill MAC, IP, IPMask, IPBcast info */ fillIfInfo(); /* opens device for receiving */ handle = pcap_open_live(deviceptr, SNAP_LEN, 1, 1000, errbuf); if (handle == NULL) { fprintf(stderr, "Couldn't open device %s: %s\n", deviceptr, errbuf); return false; } /* make sure we're capturing on an Ethernet device [2] */ if (pcap_datalink(handle) != DLT_EN10MB) { sprintf(errbuf, "%s is not an Ethernet.", deviceptr); fprintf(stderr, "%s is not an Ethernet\n", deviceptr); return false; } /* compile the filter expression */ if (pcap_compile(handle, &fp, filter_exp, 0, 0) == -1) { strcpy(errbuf, pcap_geterr(handle)); fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, errbuf); return false; } /* apply the compiled filter */ if (pcap_setfilter(handle, &fp) == -1) { strcpy(errbuf, pcap_geterr(handle)); fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, errbuf); return false; } terminated = false; /* start main thread */ QThread::start(); return true; } void Arp::stop() { terminated = true; if (!isFinished()) wait(); if (device != NULL) { delete [] device; device = NULL; } } void Arp::run() { struct pcap_pkthdr *header; const u_char *packet; while(!terminated) { /* retrieve packet */ if (pcap_next_ex(handle, &header, &packet) != 1) continue; /* parse packet */ parsePacket(header, packet); } pcap_freecode(&fp); pcap_close(handle); } void Arp::parsePacket(const struct pcap_pkthdr *hdr, const u_char *packet) { struct ether_header *eptr; struct arp_header *aptr; arp_t packet_data; eptr = (struct ether_header *) packet; /* ether type must be ARP */ if (ntohs(eptr->ether_type) == ETHERTYPE_ARP) { aptr = (struct arp_header *) (packet + ETHER_HDR_LEN); /* Only IPv4 and Ethernet is supported */ if (ntohs(aptr->hw_type) == HW_TYPE_ETHERNET && ntohs(aptr->proto_type) == PROTO_TYPE_IP) { /* prepare event structure */ packet_data.arp_operation = ntohs(aptr->opcode); packet_data.arp_mac_src = macToQString(aptr->source_add); packet_data.arp_mac_dst = macToQString(aptr->dest_add); packet_data.arp_ip_src = ipToQString(aptr->source_ip); packet_data.arp_ip_dst = ipToQString(aptr->dest_ip); packet_data.ether_mac_dst = macToQString(eptr->ether_dhost); packet_data.ether_mac_src = macToQString(eptr->ether_shost); packet_data.time = QDateTime::fromTime_t(hdr->ts.tv_sec); /* emit events */ emit received(packet_data); if (packet_data.arp_operation == ARP_AR_REQUEST) { emit requestArp(packet_data); } else if (packet_data.arp_operation == ARP_AR_REPLY) { emit replyArp(packet_data); } else if (packet_data.arp_operation == ARP_RA_REQUEST) { emit requestRArp(packet_data); } else if (packet_data.arp_operation == ARP_RA_REPLY) { emit replyRArp(packet_data); } } } } QString Arp::macToQString(const u_int8_t *pbyMacAddressInBytes) { const char cSep = ':'; QString data; data.sprintf("%02x%c%02x%c%02x%c%02x%c%02x%c%02x", pbyMacAddressInBytes[0] & 0xff, cSep, pbyMacAddressInBytes[1]& 0xff, cSep, pbyMacAddressInBytes[2]& 0xff, cSep, pbyMacAddressInBytes[3]& 0xff, cSep, pbyMacAddressInBytes[4]& 0xff, cSep, pbyMacAddressInBytes[5]& 0xff); return data; } QString Arp::ipToQString(const unsigned char *pbyIPAddressInBytes) { QString data; data.sprintf("%d.%d.%d.%d", pbyIPAddressInBytes[0] & 0xff, pbyIPAddressInBytes[1] & 0xff, pbyIPAddressInBytes[2] & 0xff, pbyIPAddressInBytes[3] & 0xff); return data; } u_int8_t* Arp::QStringToMac(QString mac) { struct ether_addr *ret; QByteArray ba = mac.toLatin1(); ret = ether_aton(ba.data()); return (u_int8_t*) ret; } u_int8_t* Arp::QStringToIp(QString ip) { static in_addr_t ret; QByteArray ba = ip.toLatin1(); ret = inet_addr(ba.data()); return (u_int8_t *) &ret; } bool Arp::isRunning() { return !terminated; } bool Arp::sendArp(const arp_t &data) { //struct sockaddr addr; void *ptr; if (device == NULL) return false; /* alocate packet */ int packet_len = sizeof(struct ether_header) + sizeof(struct arp_header); u_char* packet = new u_char[packet_len]; /* cast parts of packet to structs */ struct ether_header* ether_packet = (struct ether_header*) packet; struct arp_header* arp_packet = (struct arp_header*) (packet + sizeof(struct ether_header)); /* fill in ethernet frame header */ ptr = QStringToMac(data.ether_mac_dst); if (ptr == NULL) return false; memcpy(ether_packet->ether_dhost, ptr, ETH_ALEN); ptr = QStringToMac(data.ether_mac_src); if (ptr == NULL) return false; memcpy(ether_packet->ether_shost, ptr, ETH_ALEN); ether_packet->ether_type = htons(ETHERTYPE_ARP); /* fill in arp packet data */ arp_packet->hw_type = htons(HW_TYPE_ETHERNET); arp_packet->proto_type = htons(PROTO_TYPE_IP); arp_packet->ha_len = ETH_ALEN; arp_packet->pa_len = IP_ALEN; arp_packet->opcode = htons(data.arp_operation); ptr = QStringToMac(data.arp_mac_src); if (ptr == NULL) return false; memcpy(&arp_packet->source_add, ptr, ETH_ALEN); ptr = QStringToIp(data.arp_ip_src); if (ptr == NULL) return false; memcpy(&arp_packet->source_ip, ptr, IP_ALEN); ptr = QStringToMac(data.arp_mac_dst); if (ptr == NULL) return false; memcpy(&arp_packet->dest_add, ptr, ETH_ALEN); ptr = QStringToIp(data.arp_ip_dst); if (ptr == NULL) return false; memcpy(&arp_packet->dest_ip, ptr, IP_ALEN); /* send packet */ if (pcap_sendpacket(handle, packet, packet_len) != 0) { strcpy(errbuf, pcap_geterr(handle)); fprintf(stderr,"\nError sending the packet: %s\n", errbuf); delete [] packet; return false; } /* call parser for local echo */ pcap_pkthdr hdr; hdr.caplen = packet_len; hdr.len = packet_len; gettimeofday(&hdr.ts, NULL); parsePacket(&hdr, packet); delete [] packet; return true; } void Arp::copyArp_t(arp_t *dst, const arp_t &src) { dst->arp_ip_dst = src.arp_ip_dst; dst->arp_ip_src = src.arp_ip_src; dst->arp_mac_dst = src.arp_mac_dst; dst->arp_mac_src = src.arp_mac_src; dst->arp_operation = src.arp_operation; dst->ether_mac_dst = src.ether_mac_dst; dst->ether_mac_src = src.ether_mac_src; dst->time = src.time; } QString Arp::arpOperationtoQString(int arp_operation) { switch(arp_operation) { case ARP_AR_REQUEST: return QObject::tr("Request"); break; case ARP_AR_REPLY: return QObject::tr("Reply"); break; case ARP_RA_REQUEST: return QObject::tr("Request reverse"); break; case ARP_RA_REPLY: return QObject::tr("Reply reverse"); break; default: return QObject::tr("Unknown"); break; } } QString Arp::mac() { struct ifreq sIfReq; // Interface request struct if_nameindex *pIfList; // Ptr to interface name index struct if_nameindex *pListSave; // Ptr to interface name index QString macAddress = QString(); u_int8_t mac[ETH_ALEN]; #ifndef SIOCGIFADDR //The kernel does not support the required ioctls return QString(); #endif //Create a socket that we can use for all of our ioctls int s = socket(PF_INET, SOCK_STREAM, 0); if (s < 0) { // Socket creation failed, this is a fatal error printf( "File %s: line %d: Socket failed\n", __FILE__, __LINE__ ); return QString(); } //Obtain a list of dynamically allocated structures pListSave = if_nameindex(); //Walk thru the array returned and query for each interface's address for (pIfList = pListSave; pIfList != NULL; pIfList++) { //Determine if we are processing the interface that we are interested in if (strcmp(pIfList->if_name, device)) //Nope, check the next one in the list continue; strncpy(sIfReq.ifr_name, pIfList->if_name, IF_NAMESIZE); //Get the MAC address for this interface if (ioctl(s, SIOCGIFHWADDR, &sIfReq) != 0) { //We failed to get the MAC address for the interface printf( "File %s: line %d: Ioctl failed\n", __FILE__, __LINE__ ); return( 0 ); } memcpy(&mac, &sIfReq.ifr_ifru.ifru_hwaddr.sa_data, ETH_ALEN); macAddress = macToQString((u_int8_t *)&mac); break; } //Clean up things and return if_freenameindex(pListSave); close(s); return macAddress; } QString Arp::arp_tToQString(const arp_t &packet) { if (packet.arp_operation == ARP_AR_REQUEST) { if (packet.arp_ip_src == packet.arp_ip_dst && packet.arp_mac_dst == "00:00:00:00:00:00" && packet.ether_mac_dst == "ff:ff:ff:ff:ff:ff") { return QObject::tr("Gratuitous ARP for %1 (Request)? Asked by %2.").arg(packet.arp_ip_dst, packet.arp_mac_src); } else if (packet.arp_ip_src == "0.0.0.0") { return QObject::tr("Is IP address %1 used? Asked by %2.").arg(packet.arp_ip_dst, packet.arp_mac_src); } else { return QObject::tr("Who has %1? Tell %2 (%3).").arg(packet.arp_ip_dst, packet.arp_ip_src, packet.arp_mac_src); } } else if (packet.arp_operation == ARP_AR_REPLY) { if (packet.arp_ip_src == packet.arp_ip_dst && packet.arp_mac_src == packet.arp_mac_dst) { return QObject::tr("Gratuitous ARP for %1 (Reply)? From %2.").arg(packet.arp_ip_dst, packet.arp_mac_src); } else { return QObject::tr("%1 is at %2. Asked by %3 (%4).").arg(packet.arp_ip_src, packet.arp_mac_src, packet.arp_ip_dst, packet.arp_mac_dst); } } else { return QObject::tr("%1 (%2) from %3 (%4) to %5 (%6).").arg(Arp::arpOperationtoQString(packet.arp_operation), QString::number(packet.arp_operation), packet.arp_ip_src, packet.arp_mac_src, packet.arp_ip_dst, packet.arp_mac_dst); } } void Arp::fillIfInfo() { pcap_if_t *alldevs = NULL; pcap_if_t *dev = NULL; pcap_addr_t *addr; if (pcap_findalldevs(&alldevs, errbuf) == -1) { //TODO exception fprintf(stderr, "Couldn't find any device: %s\n", errbuf); return; } /* Print the list */ for(dev=alldevs; dev; dev=dev->next) { if (strcmp(dev->name, device) == 0) { for(addr=dev->addresses; addr; addr=addr->next) { if (addr->addr->sa_family != AF_INET) continue; if (addr->addr) memcpy(&_ip, &((struct sockaddr_in *)addr->addr)->sin_addr.s_addr, IP_ALEN); if (addr->netmask) memcpy(&_ipMask, &((struct sockaddr_in *)addr->netmask)->sin_addr.s_addr, IP_ALEN); if (addr->broadaddr) memcpy(&_ipBcast, &((struct sockaddr_in *)addr->broadaddr)->sin_addr.s_addr, IP_ALEN); break; } } } pcap_freealldevs(alldevs); } QString Arp::ip() { return ipToQString(_ip); } QString Arp::ipMask() { return ipToQString(_ipMask); } QString Arp::ipBcast() { return ipToQString(_ipBcast); } QString Arp::ipFrom() { unsigned char ip[IP_ALEN]; int i; for(i=0; i < IP_ALEN; i++) { ip[i] = _ip[i] & _ipMask[i]; } ip[IP_ALEN - 1]++; return ipToQString(&ip[0]); } QString Arp::ipTo() { unsigned char ip[IP_ALEN]; memcpy(&ip, &_ipBcast, IP_ALEN); ip[IP_ALEN - 1]--; return ipToQString(&ip[0]); }