/* * PortMonitor/G Copyright (c) 2003-2004, Max Vilimpoc, http://vilimpoc.org/research/ * Released under the GNU GPL, version 2, or any later version. * If you do use the code or find it useful, I'd love to hear about it. * * PortMonitor/G includes software (libpcap/winpcap) developed by the Politecnico di Torino, and its contributors. * '' includes software (libsdl) Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga and * released under the GNU LGPL. */ /* * Copyright (c) 1999 - 2002 * Politecnico di Torino. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: * ``This product includes software developed by the Politecnico * di Torino, and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #include #include #include #include "SDL.h" #include "SDL_thread.h" #include #include #include #define DLENGTH 256 #define BLOCKSIZE 2 #define SCREEN_WIDTH (DLENGTH * BLOCKSIZE) #define SCREEN_HEIGHT (DLENGTH * BLOCKSIZE) #define SCREEN_DEPTH 32 #ifndef NDEBUG #define ASSERTMSG(EXP,MSG) ( (EXP) ? (void)0 : (cerr << "Assertion failed: " << __FILE__ << "(" << __LINE__ << "): " #EXP << MSG << endl,exit(-1)) ) #endif enum { STOPPED, RUNNING }; int F_EVENT_LOOP = RUNNING; int F_WPCAP = RUNNING; int F_UI_RUN = RUNNING; int F_SWINGBUFFERS = RUNNING; SDL_Surface *screen, *blitbuffer; unsigned int PortMapCumulative[65536]; using namespace std; set PortMapSetA, PortMapSetB; set *BufToWrite, *BufToRead; SDL_mutex *writelock, *readlock; int FetchIFace(void) { pcap_if_t *AllDevs, *Dev; char errbuf[PCAP_ERRBUF_SIZE + 1]; unsigned int IFace, ICnt = 0; cout << "Please select an interface: " << endl; if (pcap_findalldevs(&AllDevs, errbuf) == -1) { cerr << "Error in pcap_findalldevs(): " << errbuf << endl; exit(1); // can I replace this with throw()? } /* print the list of interfaces */ for (Dev = AllDevs; Dev; Dev = Dev->next) { cout << ++ICnt << ". " << Dev->name << endl; if (Dev->description) cout << Dev->description << endl; else cout << "No description." << endl; } if (ICnt == 0) { cerr << "No interfaces found! Make sure WinPcap is installed." << endl; return 0; } cout << "Select one of the above interfaces: " << endl; cin >> IFace; pcap_freealldevs(AllDevs); if (IFace < 1 || IFace > ICnt) exit(1); return IFace; } int tSwingBuffers(void *unused) { // every second, the read and write buffers should be checked for a switch. // but only if the read buffer is empty (meaning that the tUIHandler finished blitting all ports to the screen) // and only if the write buffer has stuff that needs to be displayed. set *temp = 0; while (F_SWINGBUFFERS == RUNNING) { // TODO: add a wait on conditional here, wait for tPacketNabber to say go. if (BufToWrite->size() > 0 && BufToRead->size() == 0) { // lock the mutex, flip the pointers. SDL_mutexP(writelock); SDL_mutexP(readlock); temp = BufToRead; BufToRead = BufToWrite; BufToWrite = temp; SDL_mutexV(readlock); SDL_mutexV(writelock); // unlock the mutex } // else // how about waiting for a condition signal to be set? SDL_Delay(300); } cout << "Shutting down tSwingBuffers()." << endl; return 0; } int tPacketNabber(void *unused) { cout << "Starting up tPacketNabber()." << endl; pcap_if_t *AllDevs, *Dev; pcap_t *fp; unsigned int IFace, i; char errbuf[PCAP_ERRBUF_SIZE]; int res; struct pcap_pkthdr *header; u_char *pkt_data; union { unsigned short port; unsigned char b[2]; }; // Initialize winpcap. IFace = FetchIFace(); if (pcap_findalldevs(&AllDevs, errbuf) == -1) { cerr << "Error in pcap_findalldevs: " << errbuf << endl; exit(1); } /* Jump to the selected adapter */ for(Dev = AllDevs, i = 0; i < IFace - 1; Dev = Dev->next, i++); /* Open the device */ if ( (fp = pcap_open_live(Dev->name, 100, 1, 20, errbuf) ) == NULL) { cerr << "Error opening adapter: " << errbuf << endl; return -1; } // Check blocking mode. cout << "blocking mode: " << pcap_getnonblock(fp, errbuf); if (pcap_setnonblock(fp, 1, errbuf) == -1) { cerr << "pcap_setnonblock() call failed." << endl; } // Start nabbing packets. // TODO: packet capture throttle. // TODO: set up a conditional variable that controls tSwingBuffers? while (F_WPCAP == RUNNING) { // printf("p"); res = pcap_next_ex(fp, &header, &pkt_data); // grab next packet off iface if (res == 0) continue; if (res == -1) { cerr << "Error reading the packets: " << pcap_geterr(fp) << endl; return -1; } // We need an fps throttle, so when the packets are flying in, the RefreshRate slows down. // We should control the refresh rate from the packet capture thread, because it has the knowledge. // packets per second // ports per second // printf("%ld:%ld (%ld)\n", header->ts.tv_sec, header->ts.tv_usec, header->len); // printf("."); // Check for IP, then TCP, then print only the source port and destination port. if((pkt_data[0x0c] == 0x08) && (pkt_data[0x0d] == 0x00)) // check for packet type == IP. { cout << "c"; b[0] = pkt_data[0x24]; b[1] = pkt_data[0x25]; PortMapCumulative[port]++; // only this thread writes the cumulative portmap, no need to lock. SDL_mutexP(writelock); BufToWrite->insert(port); // have to lock this op, in case tSwingBuffers is in the middle of swapping ptrs. SDL_mutexV(writelock); // cout << "(port: " << port << ")"; } } cout << "Shutting down tPacketNabber()." << endl; pcap_freealldevs(AllDevs); pcap_close(fp); return 0; } int tUIHandler(void *unused) { cout << "Starting up tUIHandler()." << endl; SDL_Rect r; r.w = BLOCKSIZE; r.h = BLOCKSIZE; Uint32 on_color = 0x00FFFFFF; Uint32 off_color = 0x00404040; SDL_Rect runstat; runstat.x = SCREEN_WIDTH - 10; runstat.y = SCREEN_HEIGHT - 10; runstat.w = 10; runstat.h = 10; Uint32 runstat_color = 0x00FFFFFF; Uint32 now = SDL_GetTicks(); Uint32 fps_denom; double fps = 0.0; union { short int port; unsigned char b[2]; }; while (F_UI_RUN == RUNNING) { if (SDL_GetTicks() - now > 30) { SDL_FillRect(screen, &runstat, runstat_color); runstat_color ^= 0x00FFFFFF; SDL_Flip(screen); now = SDL_GetTicks(); } SDL_mutexP(readlock); // is there a way to suspend this thread on the condition that swingbuffers sets? // within critical section: if there's nothing goin' on, unlock mutex, pause, then continue; if (BufToRead->size() == 0) { SDL_mutexV(readlock); /* SDL_Delay(3); */ continue; } // if there *is* something going on, process it. set::iterator s = BufToRead->begin(); set::iterator f = BufToRead->end(); while (s != f) { port = *s; r.y = b[0] * BLOCKSIZE; r.x = b[1] * BLOCKSIZE; SDL_FillRect(screen, &r, on_color); s++; } SDL_Flip(screen); SDL_Delay(20); s = BufToRead->begin(); while (s != f) { port = *s; r.y = b[0] * BLOCKSIZE; r.x = b[1] * BLOCKSIZE; SDL_FillRect(screen, &r, off_color); s++; } // repeat, but unset all of the previously blinked ports? BufToRead->clear(); SDL_mutexV(readlock); SDL_Flip(screen); now = SDL_GetTicks(); /* fps_denom = SDL_GetTicks() - now; fps = 1000.0 / (fps_denom + 0.001); // let's not div/0 now. now = SDL_GetTicks(); printf("u:%.2f", fps); */ } cout << "Shutting down tUIHandler()." << endl; return 0; } /* int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { */ int main(int argc, char **argv) { // Initialize cumulative PortMap array to all 0's. memset(PortMapCumulative, 0, sizeof(PortMapCumulative)); BufToWrite = &PortMapSetA; BufToRead = &PortMapSetB; // Initialize writelock mutex. writelock = SDL_CreateMutex(); readlock = SDL_CreateMutex(); // Initialize SDL. if (SDL_Init(SDL_INIT_TIMER|SDL_INIT_VIDEO) == -1) { cerr << "SDL_Init failed in PortMonitorG.cpp: " << SDL_GetError() << endl; exit(-1); } atexit(SDL_Quit); screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_DEPTH, SDL_HWSURFACE | SDL_DOUBLEBUF); if (screen == NULL) { cerr << "SDL_SetVideoMode failed in PortMonitorG.cpp: " << SDL_GetError() << endl; return -2; } cout << "SDL_SetVideoMode() called successfully." << endl; /* blitbuffer = SDL_CreateRGBSurface(SDL_HWSURFACE, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_DEPTH, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); if (blitbuffer == NULL) { printf("SDL_CreateRGBSurface failed in PortMonitorG.cpp: %s\n", SDL_GetError()); return -3; } printf("SDL_CreateRGBSurface() called successfully.\n"); */ SDL_WM_SetCaption("PortMonitor/G", "GasMask"); SDL_WM_SetIcon(SDL_LoadBMP("gasmask-256.bmp"), NULL); // Initialize winpcap thread. // SDL_Thread *winpcap_thread = SDL_CreateThread(tPacketNabber, NULL); if (winpcap_thread == NULL) { cerr << "Unable to create winpcap_thread: " << SDL_GetError() << endl; return 0; } // Initialize graphics handling thread. // SDL_Thread *graphics_thread = SDL_CreateThread(tUIHandler, NULL); if (graphics_thread == NULL) { cerr << "Unable to create graphics_thread: " << SDL_GetError() << endl; return 0; } // Initialize swinging buffer thread. // SDL_Thread *swingbuffer_thread = SDL_CreateThread(tSwingBuffers, NULL); if (swingbuffer_thread == NULL) { cerr << "swingbuffer_thread creation failed." << SDL_GetError() << endl; return 0; } /* // Can we pop up a wxFrame to the right? wxFrame * frame = new wxFrame((wxFrame *) NULL, -1, "PortMonitor/G Control Frame", wxPoint(500, 10), wxSize(50, 50)); frame->CreateStatusBar(); frame->SetStatusText("PortMonitor/G v0.8.5 - coded 11:29 AM 5/13/2004"); frame->Show(TRUE); */ SDL_Event event; while (F_EVENT_LOOP == RUNNING) { if (SDL_PollEvent(&event) == 1) { // pull an event off the stack / implicitly update SDL window PumpEvent(). switch (event.type) { case SDL_MOUSEMOTION: printf("Mouse moved by %d,%d to (%d,%d).\n", event.motion.xrel, event.motion.yrel, event.motion.x, event.motion.y); break; case SDL_MOUSEBUTTONDOWN: printf("Mouse button %d pressed at (%d,%d).\n", event.button.button, event.button.x, event.button.y); break; case SDL_SYSWMEVENT: // TODO: suspend tSwingBuffers and tUIHandler when window is minimized. printf("SDL_SYSWMEVENT signal received.\n"); break; case SDL_VIDEOEXPOSE: // TODO: add handler for when parts/entire window is obscured. // TODO: suspend / unsuspend tSwingBuffers and tUIHandler when window is minimized. printf("SDL_VIDEOEXPOSE signal received.\n"); break; case SDL_QUIT: printf("SDL_QUIT signal received.\n"); F_EVENT_LOOP = STOPPED; } } } // shutdown is order dependent to ensure buffers are emptied. F_WPCAP = STOPPED; SDL_WaitThread(winpcap_thread, NULL); cout << "winpcap_thread stopped." << endl; F_UI_RUN = STOPPED; SDL_WaitThread(graphics_thread, NULL); cout << "graphics_thread stopped." << endl; F_SWINGBUFFERS = STOPPED; SDL_WaitThread(swingbuffer_thread, NULL); cout << "swingbuffer_thread stopped." << endl; // add diagnostics: final dump of buffers (should always be empty at close) cout << endl << endl; if (BufToWrite->size()) { cout << "BufToWrite Size: " << BufToWrite->size() << endl; cout << "Contents of BufToWrite: " << endl; set::iterator e = BufToWrite->begin(); while (e != BufToWrite->end()) { cout << *e << " "; e++; } } cout << endl << endl; if (BufToRead->size()) { cout << "BufToRead Size: " << BufToRead->size() << endl; cout << "Contents of BufToRead: " << endl; set::iterator e = BufToRead->begin(); while (e != BufToRead->end()) { cout << *e << " "; e++; } } cout << endl << endl; // Match this against PortMapCumulative. for (int i = 0; i < 65536; i++) { if (PortMapCumulative[i]) cout << i << ": " << PortMapCumulative[i] << endl; } SDL_DestroyMutex(readlock); SDL_DestroyMutex(writelock); return 0; }