X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fnetvis.cpp;h=0e2378fd689ac6ee9efb96a6d77a0ff9af10efc9;hb=e4b57e21ec2bc7f99c182eea23ecec297e111799;hp=e0148d908ce089915b7b3f13475e6ceac2a18a65;hpb=f3939c5da4add9af55a26293c99f0f013052cc25;p=netvis.git diff --git a/source/netvis.cpp b/source/netvis.cpp index e0148d9..0e2378f 100644 --- a/source/netvis.cpp +++ b/source/netvis.cpp @@ -5,366 +5,426 @@ Copyright @ 2008 Mikko Rasa, Mikkosoft Productions Distributed unter the GPL */ -#include #include #include #include #include -#include -#include -#include -#include -#include +#include #include +#include +#include #include #include #include #include #include #include -#include +#include +#include #include #include +#include "history.h" #include "host.h" #include "netvis.h" #include "packet.h" +#include "port.h" #include "resolver.h" using namespace std; using namespace Msp; NetVis::NetVis(int argc, char **argv): + pcap(0), + resolver(0), + wnd(0), + font(0), max_hosts(1000), max_visible_hosts(30), - draw_labels(true), - blend(true), frames(0) { if(argc<2) - throw UsageError("No interface given"); - iface=argv[1]; -} + throw usage_error("No interface given"); + iface = argv[1]; -int NetVis::main() -{ - char err[1024]; - pcap=pcap_open_live(iface.c_str(), 128, true, 0, err); + char err[PCAP_ERRBUF_SIZE]; + pcap_if_t *devs; + if(pcap_findalldevs(&devs, err)==-1) + throw runtime_error(err); + + pcap = pcap_open_live(iface.c_str(), 128, true, 0, err); if(!pcap) - throw Exception(err); + throw runtime_error(err); if(pcap_setnonblock(pcap, true, err)==-1) - throw Exception(err); + throw runtime_error(err); + + for(pcap_if_t *d=devs; d; d=d->next) + if(iface==d->name) + { + for(pcap_addr_t *a=d->addresses; a; a=a->next) + { + if(a->addr->sa_family==AF_INET) + { + Address addr(ntohl(reinterpret_cast(a->addr)->sin_addr.s_addr)); + if(a->netmask) + addr.set_mask(Address(ntohl(reinterpret_cast(a->netmask)->sin_addr.s_addr))); + localnets.push_back(addr); + } + else if(a->addr->sa_family==AF_INET6) + { + Address addr(reinterpret_cast(a->addr)->sin6_addr); + if(a->netmask) + addr.set_mask(Address(reinterpret_cast(a->netmask)->sin6_addr)); + localnets.push_back(addr); + } + } + } + + pcap_freealldevs(devs); - pcap_lookupnet(iface.c_str(), &localnet, &localnet_mask, err); - localnet=ntohl(localnet); - localnet_mask=ntohl(localnet_mask); + resolver = new Resolver; - dpy=new Graphics::Display; - wnd=new Graphics::Window(*dpy, 1024, 768); - glc=new Graphics::GLContext(*wnd); + wnd = new Graphics::SimpleGLWindow(1024, 768); wnd->set_title("NetVis"); wnd->signal_close.connect(sigc::bind(sigc::mem_fun(this, &NetVis::exit), 0)); - wnd->signal_key_press.connect(sigc::mem_fun(this, &NetVis::key_press)); wnd->show(); - GL::enable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GL::Blend::alpha().bind(); - font=new GL::Font; + font = new GL::Font; DataFile::load(*font, "dejavu-10.font"); - font_tex=new GL::Texture2D; - DataFile::load(*font_tex, "dejavu-10.tex"); - font->set_texture(*font_tex); - catch_signal(SIGINT); + history = new History(*this, 301, 100); - resolver=new Resolver; - - //set_loop_mode(TICK_BUSY); - - Application::main(); + catch_signal(SIGINT); +} +NetVis::~NetVis() +{ + delete history; delete resolver; delete font; - delete font_tex; - delete glc; delete wnd; - delete dpy; - - cout<::iterator i=hosts.begin(); i!=hosts.end(); ++i) + for(map::iterator i=hosts.begin(); i!=hosts.end(); ++i) + delete i->second; + for(map::iterator i=disabled_hosts.begin(); i!=disabled_hosts.end(); ++i) delete i->second; - for(map::iterator i=disabled_hosts.begin(); i!=disabled_hosts.end(); ++i) + for(map::iterator i=ports.begin(); i!=ports.end(); ++i) delete i->second; for(list::iterator i=packets.begin(); i!=packets.end(); ++i) delete *i; - - return exit_code; } void NetVis::tick() { - Msp::Time::TimeStamp t=Msp::Time::now(); + Msp::Time::TimeStamp t = Msp::Time::now(); Msp::Time::TimeDelta dt; if(tick_t) - dt=t-tick_t; - tick_t=t; + dt = t-tick_t; + tick_t = t; if(tick_t>fps_t+Msp::Time::sec) { - fps=frames/((tick_t-fps_t)/Msp::Time::sec); - fps_t=tick_t; - frames=0; + fps = frames/((tick_t-fps_t)/Msp::Time::sec); + fps_t = tick_t; + frames = 0; } - dpy->tick(); + wnd->get_display().tick(); + + while(pcap_dispatch(pcap, -1, &capture_handler, reinterpret_cast(this))>0) ; + + resolver->tick(); + history->tick(tick_t); + + float min_activity = numeric_limits::max(); + for(map::iterator i=hosts.begin(); i!=hosts.end(); ++i) { - Debug::ProfilingScope s(profiler, "capture"); - while(pcap_dispatch(pcap, -1, &capture_handler, reinterpret_cast(this))>0) ; + i->second->tick(dt); + min_activity = min(min_activity, i->second->get_activity()); } - + float del_limit = pow(10, 6-0.1*static_cast(max_hosts-hosts.size()-disabled_hosts.size())); + for(map::iterator i=disabled_hosts.begin(); i!=disabled_hosts.end();) { - Debug::ProfilingScope s(profiler, "tick"); - - resolver->tick(); + i->second->tick(dt); - float min_activity=numeric_limits::max(); - for(map::iterator i=hosts.begin(); i!=hosts.end(); ++i) + if(i->second->get_activity()>min_activity) { - i->second->tick(dt); - min_activity=min(min_activity, i->second->get_activity()); + i->second->set_active(true); + hosts.insert(*i); + for(unsigned j=0; j<100; ++j) + i->second->tick(100*Time::msec); + disabled_hosts.erase(i++); } - float del_limit=pow(10, 6-0.1*(max_hosts-hosts.size()-disabled_hosts.size())); - for(map::iterator i=disabled_hosts.begin(); i!=disabled_hosts.end();) + else if(i->second->get_activity()second->tick(dt); - - if(i->second->get_activity()>min_activity) - { - i->second->set_active(true); - hosts.insert(*i); - disabled_hosts.erase(i++); - } - else if(i->second->get_activity()second; - disabled_hosts.erase(i++); - } - else - ++i; + resolver->cancel(i->second); + delete i->second; + disabled_hosts.erase(i++); } + else + ++i; + } - if(hosts.size()>max_visible_hosts) - { - list activity; - for(map::iterator i=hosts.begin(); i!=hosts.end(); ++i) - activity.push_back(i->second->get_activity()); - activity.sort(); - - list::iterator j=activity.begin(); - advance(j, activity.size()-max_visible_hosts); - float limit=*j; + if(hosts.size()>max_visible_hosts) + { + list activity; + for(map::iterator i=hosts.begin(); i!=hosts.end(); ++i) + activity.push_back(i->second->get_activity()); + activity.sort(); - for(map::iterator i=hosts.begin(); i!=hosts.end();) - { - if(i->second->get_activity()second->set_active(false); - disabled_hosts.insert(*i); - hosts.erase(i++); - } - else - ++i; - } - } + list::iterator j = activity.begin(); + advance(j, activity.size()-max_visible_hosts); + float limit = *j; - for(list::iterator i=packets.begin(); i!=packets.end();) + for(map::iterator i=hosts.begin(); i!=hosts.end();) { - (*i)->tick(dt); - if((*i)->get_stale()) + if(i->second->get_activity()second->set_active(false); + disabled_hosts.insert(*i); + hosts.erase(i++); } else ++i; } } + for(map::iterator i=ports.begin(); i!=ports.end();) { - Debug::ProfilingScope s(profiler, "render"); - glClear(GL_COLOR_BUFFER_BIT); + i->second->tick(dt); - GL::matrix_mode(GL::PROJECTION); - GL::load_identity(); - GL::ortho_centered(1024, 768); - GL::matrix_mode(GL::MODELVIEW); - GL::load_identity(); + if(!i->second->is_registered() && i->second->get_activity()<0.1) + { + delete i->second; + ports.erase(i++); + } + else + ++i; + } - for(map::iterator i=hosts.begin(); i!=hosts.end(); ++i) - i->second->render(); - if(draw_labels) + for(list::iterator i=packets.begin(); i!=packets.end();) + { + (*i)->tick(dt); + if((*i)->get_stale()) { - glColor4f(1.0, 1.0, 1.0, 1.0); - for(map::iterator i=hosts.begin(); i!=hosts.end(); ++i) - i->second->render_label(); - GL::Texture::unbind(); + delete *i; + i = packets.erase(i); } + else + ++i; + } + + render(); + wnd->swap_buffers(); + + ++frames; +} + +void NetVis::render() +{ + GL::Framebuffer::system().clear(GL::COLOR_BUFFER_BIT); + + GL::MatrixStack::projection() = GL::Matrix::ortho_centered(1024, 768); + GL::MatrixStack::modelview() = GL::Matrix(); + + for(map::iterator i=hosts.begin(); i!=hosts.end(); ++i) + i->second->render(); + { GL::Immediate imm((GL::COLOR4_UBYTE, GL::VERTEX2)); imm.begin(GL::QUADS); for(list::iterator i=packets.begin(); i!=packets.end(); ++i) (*i)->render(imm); imm.end(); + } - GL::push_matrix(); - GL::translate(-500, 360, 0); - unsigned n=0; - for(map::iterator i=port_colors.begin(); (i!=port_colors.end() && n<20); ++i, ++n) - { - GL::Color &color=i->second; - - imm.begin(GL::QUADS); - imm.color(color.r, color.g, color.b, color.a); - for(unsigned x=0; x<=4; x+=2) - { - imm.vertex(x+0, 0); - imm.vertex(x+10, 0); - imm.vertex(x+10, 10); - imm.vertex(x+0, 10); - } - imm.end(); - - GL::translate(0, -12, 0); - } - GL::pop_matrix(); - - GL::push_matrix(); - if(draw_labels) + GL::MatrixStack::modelview() = GL::Matrix::translation(-500, 360, 0); + unsigned n = 0; + for(map::iterator i=ports.begin(); (i!=ports.end() && n<50); ++i) + { + float act = i->second->get_activity(); + if((i->second->is_registered() && act>1) || act>200) { - GL::push_matrix(); - GL::translate(-484, 361, 0); - GL::scale_uniform(10); - glColor4f(1.0, 1.0, 1.0, 1.0); - n=0; - for(map::iterator i=port_colors.begin(); (i!=port_colors.end() && n<20); ++i, ++n) - { - font->draw_string(format("%d", i->first)); - - GL::translate(0, -1.2, 0); - } - GL::pop_matrix(); - GL::Texture::unbind(); + i->second->render(); + GL::MatrixStack::modelview() *= GL::Matrix::translation(0, -12, 0); + ++n; } - GL::pop_matrix(); - - GL::push_matrix(); - GL::translate(-500, -360, 0); - GL::scale_uniform(10); - font->draw_string(format("%d hosts", hosts.size()+disabled_hosts.size())); - GL::translate(0, -1.2, 0); - font->draw_string(format("%.2f fps", fps)); - GL::pop_matrix(); - GL::Texture::unbind(); - - glc->swap_buffers(); } - ++frames; + GL::MatrixStack::modelview() = GL::Matrix::translation(-500, -348, 0); + GL::MatrixStack::modelview() *= GL::Matrix::scaling(10); + font->draw_string(format("%d hosts", hosts.size()+disabled_hosts.size())); + GL::MatrixStack::modelview() *= GL::Matrix::translation(0, -1.2, 0); + font->draw_string(format("%d ports", ports.size())); + GL::MatrixStack::modelview() *= GL::Matrix::translation(0, -1.2, 0); + font->draw_string(format("%.2f fps", fps)); + GL::Texture::unbind(); + + GL::MatrixStack::modelview() = GL::Matrix::translation(170, -370, 0); + history->render(); } -Host &NetVis::get_host(unsigned a) +Host &NetVis::get_host(const Address &a) { - map::iterator i=hosts.find(a); + map::iterator i = hosts.find(a); if(i!=hosts.end()) return *i->second; - i=disabled_hosts.find(a); + i = disabled_hosts.find(a); if(i!=disabled_hosts.end()) return *i->second; - Host *host=new Host(*this, a); - if((a&localnet_mask)==localnet) - host->set_local(true); + Host *host = new Host(*this, a); + for(list
::const_iterator j=localnets.begin(); j!=localnets.end(); ++j) + if(j->masked_match(a)) + host->set_local(true); resolver->push(host); host->set_position(Vector2(rand()*400.0/RAND_MAX-200.0, rand()*400.0/RAND_MAX-200.0)); - hosts[a]=host; + for(unsigned j=0; j<100; ++j) + host->tick(100*Time::msec); + hosts[a] = host; return *host; } -GL::Color &NetVis::get_port_color(unsigned port) +Port &NetVis::get_port(unsigned number) +{ + map::iterator i = ports.find(number); + if(i!=ports.end()) + return *i->second; + Port *port = new Port(*this, number); + ports[number] = port; + return *port; +} + +void NetVis::capture_handler(unsigned char *user, const pcap_pkthdr *cap, const unsigned char *data) +{ + NetVis *self = reinterpret_cast(user); + + CaptureContext ctx; + ctx.cap_hdr = cap; + const ethhdr *eth = reinterpret_cast(data); + self->handle_ethernet(ctx, eth, cap->caplen); +} + +void NetVis::handle_ethernet(CaptureContext &ctx, const ethhdr *eth, unsigned len) { - map::iterator i=port_colors.find(port); - if(i!=port_colors.end()) - return i->second; + ctx.size = ctx.cap_hdr->len-sizeof(ethhdr); - GL::Color color; - while(1) + int proto = ntohs(eth->h_proto); + if(proto==ETH_P_IP) + { + const iphdr *ip = reinterpret_cast(eth+1); + handle_ipv4(ctx, ip, len-sizeof(ethhdr)); + } + else if(proto==ETH_P_IPV6) { - color.r=rand()*1.0/RAND_MAX; - color.g=rand()*1.0/RAND_MAX; - color.b=rand()*1.0/RAND_MAX; - if(color.r>0.5 || color.g>0.5 || color.b>0.7) - break; + const ip6_hdr *ip6 = reinterpret_cast(eth+1); + handle_ipv6(ctx, ip6, len-sizeof(ethhdr)); } - color.a=0.4f; - return port_colors[port]=color; + else + IO::print("Unknown protocol in eth: %d\n", proto); } -void NetVis::key_press(unsigned key, unsigned, wchar_t) +void NetVis::handle_ipv4(CaptureContext &ctx, const iphdr *ip, unsigned len) { - if(key==46) - draw_labels=!draw_labels; - else if(key==56) + ctx.src_host = &get_host(ntohl(ip->saddr)); + if((ntohl(ip->daddr)&0xFF)!=0xFF) + ctx.dst_host = &get_host(ntohl(ip->daddr)); + + if(ip->protocol==IPPROTO_TCP) { - blend=!blend; - GL::set(GL_BLEND, blend); + const tcphdr *tcp = reinterpret_cast(ip+1); + handle_tcp(ctx, tcp, len-sizeof(iphdr)); } + else if(ip->protocol==IPPROTO_UDP) + { + const udphdr *udp = reinterpret_cast(ip+1); + handle_udp(ctx, udp, len-sizeof(iphdr)); + } + else + IO::print("Unknown protocol in ip: %d\n", ip->protocol); } -void NetVis::capture_handler(unsigned char *user, const pcap_pkthdr *, const unsigned char *data) +void NetVis::handle_ipv6(CaptureContext &ctx, const ip6_hdr *ip6, unsigned len) { - NetVis *self=reinterpret_cast(user); + ctx.src_host = &get_host(ip6->ip6_src); + if(!IN6_IS_ADDR_MULTICAST(ip6->ip6_dst.s6_addr)) + ctx.dst_host = &get_host(ip6->ip6_dst); - const ethhdr *eth=reinterpret_cast(data); - if(ntohs(eth->h_proto)==ETH_P_IP) + if(ip6->ip6_nxt==IPPROTO_TCP) { - const iphdr *ip=reinterpret_cast(eth+1); + const tcphdr *tcp = reinterpret_cast(ip6+1); + handle_tcp(ctx, tcp, len-sizeof(ip6_hdr)); + } + else if(ip6->ip6_nxt==IPPROTO_UDP) + { + const udphdr *udp = reinterpret_cast(ip6+1); + handle_udp(ctx, udp, len-sizeof(ip6_hdr)); + } + else + IO::print("Unknown next header in ip6: %d\n", ip6->ip6_nxt); +} - unsigned size=ntohs(ip->tot_len); - unsigned port=0; - if(ip->protocol==IPPROTO_TCP) - { - const tcphdr *tcp=reinterpret_cast(ip+1); - port=min(ntohs(tcp->source), ntohs(tcp->dest)); - } - else if(ip->protocol==IPPROTO_UDP) - { - const udphdr *udp=reinterpret_cast(ip+1); - port=min(ntohs(udp->source), ntohs(udp->dest)); - } - Host &shost=self->get_host(ntohl(ip->saddr)); - Host *dhost=0; - if((ntohl(ip->daddr)&0xFF)!=0xFF) - dhost=&self->get_host(ntohl(ip->daddr)); +void NetVis::handle_tcp(CaptureContext &ctx, const tcphdr *tcp, unsigned) +{ + ctx.src_port = &get_port(ntohs(tcp->source)); + ctx.dst_port = &get_port(ntohs(tcp->dest)); + handle_packet(ctx); +} - float throttle=shost.send_packet(); - if(throttle<1) +void NetVis::handle_udp(CaptureContext &ctx, const udphdr *udp, unsigned) +{ + ctx.src_port = &get_port(ntohs(udp->source)); + ctx.dst_port = &get_port(ntohs(udp->dest)); + handle_packet(ctx); +} + +void NetVis::handle_packet(CaptureContext &ctx) +{ + Port *port = 0; + if(ctx.src_port && ctx.dst_port) + { + if(ctx.src_port->is_registered()!=ctx.dst_port->is_registered()) { - self->packets.push_back(new Packet(shost, dhost, self->get_port_color(port), size)); - self->packets.back()->tick(-throttle*Msp::Time::sec); + if(ctx.src_port->is_registered()) + port = ctx.src_port; + else + port = ctx.dst_port; } + else if(ctx.src_port->get_number()get_number()) + port = ctx.src_port; + else + port = ctx.dst_port; + } + else + port = &get_port(0); - shost.add_activity(size); - if(dhost) - dhost->add_activity(size); + float throttle = ctx.src_host->send_packet(); + if(throttle<1) + { + packets.push_back(new Packet(*ctx.src_host, ctx.dst_host, port->get_color(), ctx.size)); + packets.back()->tick(-throttle*Msp::Time::sec); } + + ctx.src_host->add_activity(ctx.size); + if(ctx.dst_host) + ctx.dst_host->add_activity(ctx.size); + + if(ctx.src_port) + ctx.src_port->add_activity(ctx.size); + if(ctx.dst_port) + ctx.dst_port->add_activity(ctx.size); + + bool local_src = ctx.src_host->is_local(); + bool local_dst = (ctx.dst_host && ctx.dst_host->is_local()); + if(local_src && !local_dst) + history->activity(0, ctx.size); + else if(local_dst && !local_src) + history->activity(ctx.size, 0); } void NetVis::sighandler(int) @@ -372,4 +432,12 @@ void NetVis::sighandler(int) exit(0); } -Application::RegApp NetVis::reg; + +NetVis::CaptureContext::CaptureContext(): + cap_hdr(0), + src_host(0), + src_port(0), + dst_host(0), + dst_port(0), + size(0) +{ }