/* ARP Monitor arpmon.cpp A simple arpwatch-like pcap application. Copyright (C) 2005 Brady Alleman. All Rights Reserved. */ #include #include #include #include #include #include #include #include #include #include using namespace std; #define FILTER "arp" bool debug = false; bool dumpfile = false; bool database = false; void daemonize() { pid_t pid; pid = fork(); if (pid < 0) { // failed to fork, keep going with this process fprintf(stderr, "Failed to fork; unable to daemonize.\n"); fprintf(stderr, "Continuing in the foreground.\n"); return; } else if (pid != 0) { // fork successful, and we're the parent, time to die. exit(0); } else { // we're the child, keep going setsid(); chdir("/"); umask(0); return; } } void print_usage() { printf("ARPMon - A simple network analyzer.\n\n"); printf("Options\n"); printf("-h This screen right here.\n"); printf("-i Capture from interface specified.\n"); printf("-f Read from the specified file.\n"); printf("-d Print debugging info.\n"); printf("-D Use database.\n"); printf("-x Daemonize.\n"); printf("\nOptions -i and -f are mutually exclusive.\n"); printf("\n"); } void process_entry(char * mac, char * ip, MYSQL * db_conn) { MYSQL_RES * res; MYSQL_ROW row; char temp[255]; if (debug) printf("%s <-> %s\n", mac, ip); if (database) { snprintf(temp, 255, "SELECT id FROM arp WHERE ip = INET_ATON('%s') AND mac = CONV('%s', 16, 10)", ip, mac); mysql_query(db_conn, temp); res = mysql_store_result(db_conn); if (mysql_num_rows(res) > 0) { row = mysql_fetch_row(res); snprintf(temp, 255, "UPDATE arp SET stamp=NOW() WHERE id=%d", row[0]); mysql_query(db_conn, temp); } else { snprintf(temp, 255, "INSERT INTO arp SET ip = INET_ATON('%s'), mac = CONV('%s', 16, 10), stamp = NOW()", ip, mac); mysql_query(db_conn, temp); } mysql_free_result(res); } } void handle_packets(pcap_t * pcap_sess, MYSQL * db_conn) { u_char * packet; struct pcap_pkthdr header; char mac[20], ip[20], oldmac[20] = "", oldip[20] = ""; for (;;) { packet = (u_char *) pcap_next(pcap_sess, &header); if (packet == NULL) { if (dumpfile) { pcap_close(pcap_sess); exit(1); } continue; } if ((packet[20] != 0) || (packet[21] != 1)) { if (debug) printf("Packet isn't an ARP request.\n"); continue; } snprintf(mac, 20, "%02x%02x%02x%02x%02x%02x", packet[22], packet[23], packet[24], packet[25], packet[26], packet[27]); snprintf(ip, 20, "%d.%d.%d.%d", packet[28], packet[29], packet[30], packet[31]); if ( (strcmp(mac, oldmac) == 0) && (strcmp(ip, oldip) == 0) ) { if (debug) printf("Duplicate, not processing.\n"); } else { strncpy(oldmac, mac, 20); strncpy(oldip, ip, 20); process_entry(mac, ip, db_conn); } } } void setup_filter(pcap_t * pcap_sess) { struct bpf_program filter; if (pcap_compile(pcap_sess, &filter, FILTER, 1, 0) == -1) { printf("Filter Compile Failed. %s\n", pcap_geterr(pcap_sess)); pcap_close(pcap_sess); exit(1); } if (pcap_setfilter(pcap_sess, &filter) == -1) { printf("Filter Failed. %s\n", pcap_geterr(pcap_sess)); pcap_close(pcap_sess); exit(1); } } void db_connect(MYSQL * db_conn) { mysql_init(db_conn); mysql_real_connect(db_conn, "localhost", "nettools", "your_database_password_here", "nettools", 0, NULL, 0); } int main(int argc, char ** argv) { int opt; pcap_t * pcap_sess = NULL; char errbuf[PCAP_ERRBUF_SIZE] = "Required arguments missing."; MYSQL db_conn; while ((opt = getopt(argc, argv, "hdDxi:f:")) != -1) { switch (opt) { case 'h': print_usage(); exit(0); break; case 'i': pcap_sess = pcap_open_live(optarg, 60, 1, 500, errbuf); break; case 'f': pcap_sess = pcap_open_offline(optarg, errbuf); dumpfile = true; break; case 'd': debug = true; break; case 'D': database = true; break; case 'x': daemonize(); break; } } if (pcap_sess == NULL) { printf("ARPMon Failed. %s\n", errbuf); exit(1); } if (pcap_datalink(pcap_sess) != DLT_EN10MB) { printf("ARPMon only works on Ethernet.\n"); pcap_close(pcap_sess); exit(1); } setup_filter(pcap_sess); if (database) db_connect(&db_conn); handle_packets(pcap_sess, &db_conn); if (database) mysql_close(&db_conn); pcap_close(pcap_sess); exit(0); }