X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fnetvis.cpp;h=771af7f5db93272ee673faffc481810f81ee1164;hb=HEAD;hp=15b0cb51ecf4fcc86a80e42ba2d3324b887b9acf;hpb=7c86fe7860ade14b0387dec7ab564e6a480224b5;p=netvis.git diff --git a/source/netvis.cpp b/source/netvis.cpp index 15b0cb5..771af7f 100644 --- a/source/netvis.cpp +++ b/source/netvis.cpp @@ -9,11 +9,7 @@ Distributed unter the GPL #include #include #include -#include -#include -#include -#include -#include +#include #include #include #include @@ -23,7 +19,8 @@ Distributed unter the GPL #include #include #include -#include +#include +#include #include #include #include "history.h" @@ -46,20 +43,44 @@ NetVis::NetVis(int argc, char **argv): frames(0) { if(argc<2) - throw UsageError("No interface given"); + throw usage_error("No interface given"); iface = argv[1]; - char err[1024]; + 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_lookupnet(iface.c_str(), &localnet, &localnet_mask, err); - localnet = ntohl(localnet); - localnet_mask = ntohl(localnet_mask); + pcap_freealldevs(devs); resolver = new Resolver; @@ -68,8 +89,7 @@ NetVis::NetVis(int argc, char **argv): wnd->signal_close.connect(sigc::bind(sigc::mem_fun(this, &NetVis::exit), 0)); wnd->show(); - GL::enable(GL::BLEND); - GL::blend_func(GL::SRC_ALPHA, GL::ONE_MINUS_SRC_ALPHA); + GL::Blend::alpha().bind(); font = new GL::Font; DataFile::load(*font, "dejavu-10.font"); @@ -88,9 +108,9 @@ NetVis::~NetVis() delete wnd; pcap_close(pcap); - for(map::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) + for(map::iterator i=disabled_hosts.begin(); i!=disabled_hosts.end(); ++i) delete i->second; for(map::iterator i=ports.begin(); i!=ports.end(); ++i) delete i->second; @@ -122,13 +142,13 @@ void NetVis::tick() float min_activity = numeric_limits::max(); - for(map::iterator i=hosts.begin(); i!=hosts.end(); ++i) + for(map::iterator i=hosts.begin(); i!=hosts.end(); ++i) { 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();) + for(map::iterator i=disabled_hosts.begin(); i!=disabled_hosts.end();) { i->second->tick(dt); @@ -153,7 +173,7 @@ void NetVis::tick() if(hosts.size()>max_visible_hosts) { list activity; - for(map::iterator i=hosts.begin(); i!=hosts.end(); ++i) + for(map::iterator i=hosts.begin(); i!=hosts.end(); ++i) activity.push_back(i->second->get_activity()); activity.sort(); @@ -161,7 +181,7 @@ void NetVis::tick() advance(j, activity.size()-max_visible_hosts); float limit = *j; - for(map::iterator i=hosts.begin(); i!=hosts.end();) + for(map::iterator i=hosts.begin(); i!=hosts.end();) { if(i->second->get_activity()::iterator i=hosts.begin(); i!=hosts.end(); ++i) + for(map::iterator i=hosts.begin(); i!=hosts.end(); ++i) i->second->render(); { GL::Immediate imm((GL::COLOR4_UBYTE, GL::VERTEX2)); @@ -225,8 +242,7 @@ void NetVis::render() imm.end(); } - GL::push_matrix(); - GL::translate(-500, 360, 0); + GL::MatrixStack::modelview() = GL::Matrix::translation(-500, 360, 0); unsigned n = 0; for(map::iterator i=ports.begin(); (i!=ports.end() && n<50); ++i) { @@ -234,32 +250,27 @@ void NetVis::render() if((i->second->is_registered() && act>1) || act>200) { i->second->render(); - GL::translate(0, -12, 0); + GL::MatrixStack::modelview() *= GL::Matrix::translation(0, -12, 0); ++n; } } - GL::pop_matrix(); - GL::push_matrix(); - GL::translate(-500, -348, 0); - GL::scale_uniform(10); + 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::translate(0, -1.2, 0); + GL::MatrixStack::modelview() *= GL::Matrix::translation(0, -1.2, 0); font->draw_string(format("%d ports", ports.size())); - GL::translate(0, -1.2, 0); + GL::MatrixStack::modelview() *= GL::Matrix::translation(0, -1.2, 0); font->draw_string(format("%.2f fps", fps)); GL::Texture::unbind(); - GL::pop_matrix(); - GL::push_matrix(); - GL::translate(170, -370, 0); + GL::MatrixStack::modelview() = GL::Matrix::translation(170, -370, 0); history->render(); - GL::pop_matrix(); } -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; @@ -268,8 +279,9 @@ Host &NetVis::get_host(unsigned a) return *i->second; Host *host = new Host(*this, a); - if((a&localnet_mask)==localnet) - host->set_local(true); + 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)); for(unsigned j=0; j<100; ++j) @@ -284,80 +296,166 @@ Port &NetVis::get_port(unsigned number) if(i!=ports.end()) return *i->second; Port *port = new Port(*this, number); + if(number>=0x10000) + { + if((number&0xFF)==IPPROTO_ICMP) + port->set_name("icmp"); + else if((number&0xFF)==IPPROTO_ICMPV6) + port->set_name("icmp6"); + } ports[number] = port; return *port; } -void NetVis::capture_handler(unsigned char *user, const pcap_pkthdr *, const unsigned char *data) +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); - if(ntohs(eth->h_proto)==ETH_P_IP) + self->handle_ethernet(ctx, eth, cap->caplen); +} + +void NetVis::handle_ethernet(CaptureContext &ctx, const ethhdr *eth, unsigned len) +{ + ctx.size = ctx.cap_hdr->len-sizeof(ethhdr); + + 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) + { + const ip6_hdr *ip6 = reinterpret_cast(eth+1); + handle_ipv6(ctx, ip6, len-sizeof(ethhdr)); + } + else + IO::print("Unknown protocol in eth: %d\n", proto); +} - unsigned size = ntohs(ip->tot_len); +void NetVis::handle_ipv4(CaptureContext &ctx, const iphdr *ip, unsigned len) +{ + ctx.src_host = &get_host(ntohl(ip->saddr)); + if((ntohl(ip->daddr)&0xFF)!=0xFF) + ctx.dst_host = &get_host(ntohl(ip->daddr)); - Port *sport = 0; - Port *dport = 0; - if(ip->protocol==IPPROTO_TCP) - { - const tcphdr *tcp = reinterpret_cast(ip+1); - sport = &self->get_port(ntohs(tcp->source)); - dport = &self->get_port(ntohs(tcp->dest)); - } - else if(ip->protocol==IPPROTO_UDP) - { - const udphdr *udp = reinterpret_cast(ip+1); - sport = &self->get_port(ntohs(udp->source)); - dport = &self->get_port(ntohs(udp->dest)); - } + if(ip->protocol==IPPROTO_TCP) + { + 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 if(ip->protocol==IPPROTO_ICMP) + { + const icmphdr *icmp = reinterpret_cast(ip+1); + handle_icmp(ctx, icmp, len-sizeof(iphdr)); + } + else + IO::print("Unknown protocol in ip: %d\n", ip->protocol); +} - Port *port = 0; - if(sport && dport) - { - if(sport->is_registered()!=dport->is_registered()) - { - if(sport->is_registered()) - port = sport; - else - port = dport; - } - else if(sport->get_number()get_number()) - port = sport; - else - port = dport; - } - else - port = &self->get_port(0); +void NetVis::handle_ipv6(CaptureContext &ctx, const ip6_hdr *ip6, unsigned len) +{ + 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); + + if(ip6->ip6_nxt==IPPROTO_TCP) + { + 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 if(ip6->ip6_nxt==IPPROTO_ICMPV6) + { + const icmp6_hdr *icmp6 = reinterpret_cast(ip6+1); + handle_icmp6(ctx, icmp6, len-sizeof(ip6_hdr)); + } + else + IO::print("Unknown next header in ip6: %d\n", ip6->ip6_nxt); +} - 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) - { - self->packets.push_back(new Packet(shost, dhost, port->get_color(), size)); - self->packets.back()->tick(-throttle*Msp::Time::sec); - } +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_icmp(CaptureContext &ctx, const icmphdr *, unsigned) +{ + ctx.src_port = &get_port(0x10000|IPPROTO_ICMP); + ctx.dst_port = ctx.src_port; + handle_packet(ctx); +} - shost.add_activity(size); - if(dhost) - dhost->add_activity(size); +void NetVis::handle_icmp6(CaptureContext &ctx, const icmp6_hdr *, unsigned) +{ + ctx.src_port = &get_port(0x10000|IPPROTO_ICMPV6); + ctx.dst_port = ctx.src_port; + handle_packet(ctx); +} - if(sport) - sport->add_activity(size); - if(dport) - dport->add_activity(size); +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()) + { + 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); - if((ntohl(ip->saddr)&self->localnet_mask)==self->localnet) - self->history->activity(0, size); - else if((ntohl(ip->daddr)&self->localnet_mask)==self->localnet) - self->history->activity(size, 0); + 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) @@ -365,4 +463,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) +{ }