3 This file is part of NetVis
4 Copyright @ 2008 Mikko Rasa, Mikkosoft Productions
5 Distributed unter the GPL
12 #include <msp/core/getopt.h>
13 #include <msp/debug/profilingscope.h>
14 #include <msp/gl/blend.h>
15 #include <msp/gl/framebuffer.h>
16 #include <msp/gl/immediate.h>
17 #include <msp/gl/matrix.h>
18 #include <msp/gl/misc.h>
19 #include <msp/gl/projection.h>
20 #include <msp/gl/texture2d.h>
21 #include <msp/gl/transform.h>
22 #include <msp/io/print.h>
23 #include <msp/strings/format.h>
24 #include <msp/time/units.h>
25 #include <msp/time/utils.h>
36 NetVis::NetVis(int argc, char **argv):
42 max_visible_hosts(30),
46 throw usage_error("No interface given");
49 char err[PCAP_ERRBUF_SIZE];
51 if(pcap_findalldevs(&devs, err)==-1)
52 throw runtime_error(err);
54 pcap = pcap_open_live(iface.c_str(), 128, true, 0, err);
56 throw runtime_error(err);
58 if(pcap_setnonblock(pcap, true, err)==-1)
59 throw runtime_error(err);
61 for(pcap_if_t *d=devs; d; d=d->next)
64 for(pcap_addr_t *a=d->addresses; a; a=a->next)
66 if(a->addr->sa_family==AF_INET)
68 Address addr(ntohl(reinterpret_cast<sockaddr_in *>(a->addr)->sin_addr.s_addr));
70 addr.set_mask(Address(ntohl(reinterpret_cast<sockaddr_in *>(a->netmask)->sin_addr.s_addr)));
71 localnets.push_back(addr);
73 else if(a->addr->sa_family==AF_INET6)
75 Address addr(reinterpret_cast<sockaddr_in6 *>(a->addr)->sin6_addr);
77 addr.set_mask(Address(reinterpret_cast<sockaddr_in6 *>(a->netmask)->sin6_addr));
78 localnets.push_back(addr);
83 pcap_freealldevs(devs);
85 resolver = new Resolver;
87 wnd = new Graphics::SimpleGLWindow(1024, 768);
88 wnd->set_title("NetVis");
89 wnd->signal_close.connect(sigc::bind(sigc::mem_fun(this, &NetVis::exit), 0));
92 GL::Blend::alpha().bind();
95 DataFile::load(*font, "dejavu-10.font");
97 history = new History(*this, 301, 100);
111 for(map<Address, Host *>::iterator i=hosts.begin(); i!=hosts.end(); ++i)
113 for(map<Address, Host *>::iterator i=disabled_hosts.begin(); i!=disabled_hosts.end(); ++i)
115 for(map<unsigned, Port *>::iterator i=ports.begin(); i!=ports.end(); ++i)
117 for(list<Packet *>::iterator i=packets.begin(); i!=packets.end(); ++i)
123 Msp::Time::TimeStamp t = Msp::Time::now();
124 Msp::Time::TimeDelta dt;
129 if(tick_t>fps_t+Msp::Time::sec)
131 fps = frames/((tick_t-fps_t)/Msp::Time::sec);
136 wnd->get_display().tick();
138 while(pcap_dispatch(pcap, -1, &capture_handler, reinterpret_cast<unsigned char *>(this))>0) ;
141 history->tick(tick_t);
144 float min_activity = numeric_limits<float>::max();
145 for(map<Address, Host *>::iterator i=hosts.begin(); i!=hosts.end(); ++i)
148 min_activity = min(min_activity, i->second->get_activity());
150 float del_limit = pow(10, 6-0.1*static_cast<int>(max_hosts-hosts.size()-disabled_hosts.size()));
151 for(map<Address, Host *>::iterator i=disabled_hosts.begin(); i!=disabled_hosts.end();)
155 if(i->second->get_activity()>min_activity)
157 i->second->set_active(true);
159 for(unsigned j=0; j<100; ++j)
160 i->second->tick(100*Time::msec);
161 disabled_hosts.erase(i++);
163 else if(i->second->get_activity()<del_limit)
165 resolver->cancel(i->second);
167 disabled_hosts.erase(i++);
173 if(hosts.size()>max_visible_hosts)
175 list<float> activity;
176 for(map<Address, Host *>::iterator i=hosts.begin(); i!=hosts.end(); ++i)
177 activity.push_back(i->second->get_activity());
180 list<float>::iterator j = activity.begin();
181 advance(j, activity.size()-max_visible_hosts);
184 for(map<Address, Host *>::iterator i=hosts.begin(); i!=hosts.end();)
186 if(i->second->get_activity()<limit)
188 i->second->set_active(false);
189 disabled_hosts.insert(*i);
197 for(map<unsigned, Port *>::iterator i=ports.begin(); i!=ports.end();)
201 if(!i->second->is_registered() && i->second->get_activity()<0.1)
210 for(list<Packet *>::iterator i=packets.begin(); i!=packets.end();)
213 if((*i)->get_stale())
216 i = packets.erase(i);
228 void NetVis::render()
230 GL::Framebuffer::system().clear(GL::COLOR_BUFFER_BIT);
232 GL::MatrixStack::projection() = GL::Matrix::ortho_centered(1024, 768);
233 GL::MatrixStack::modelview() = GL::Matrix();
235 for(map<Address, Host *>::iterator i=hosts.begin(); i!=hosts.end(); ++i)
238 GL::Immediate imm((GL::COLOR4_UBYTE, GL::VERTEX2));
239 imm.begin(GL::QUADS);
240 for(list<Packet *>::iterator i=packets.begin(); i!=packets.end(); ++i)
245 GL::MatrixStack::modelview() = GL::Matrix::translation(-500, 360, 0);
247 for(map<unsigned, Port *>::iterator i=ports.begin(); (i!=ports.end() && n<50); ++i)
249 float act = i->second->get_activity();
250 if((i->second->is_registered() && act>1) || act>200)
253 GL::MatrixStack::modelview() *= GL::Matrix::translation(0, -12, 0);
258 GL::MatrixStack::modelview() = GL::Matrix::translation(-500, -348, 0);
259 GL::MatrixStack::modelview() *= GL::Matrix::scaling(10);
260 font->draw_string(format("%d hosts", hosts.size()+disabled_hosts.size()));
261 GL::MatrixStack::modelview() *= GL::Matrix::translation(0, -1.2, 0);
262 font->draw_string(format("%d ports", ports.size()));
263 GL::MatrixStack::modelview() *= GL::Matrix::translation(0, -1.2, 0);
264 font->draw_string(format("%.2f fps", fps));
265 GL::Texture::unbind();
267 GL::MatrixStack::modelview() = GL::Matrix::translation(170, -370, 0);
271 Host &NetVis::get_host(const Address &a)
273 map<Address, Host *>::iterator i = hosts.find(a);
277 i = disabled_hosts.find(a);
278 if(i!=disabled_hosts.end())
281 Host *host = new Host(*this, a);
282 for(list<Address>::const_iterator j=localnets.begin(); j!=localnets.end(); ++j)
283 if(j->masked_match(a))
284 host->set_local(true);
285 resolver->push(host);
286 host->set_position(Vector2(rand()*400.0/RAND_MAX-200.0, rand()*400.0/RAND_MAX-200.0));
287 for(unsigned j=0; j<100; ++j)
288 host->tick(100*Time::msec);
293 Port &NetVis::get_port(unsigned number)
295 map<unsigned, Port *>::iterator i = ports.find(number);
298 Port *port = new Port(*this, number);
301 if((number&0xFF)==IPPROTO_ICMP)
302 port->set_name("icmp");
303 else if((number&0xFF)==IPPROTO_ICMPV6)
304 port->set_name("icmp6");
306 ports[number] = port;
310 void NetVis::capture_handler(unsigned char *user, const pcap_pkthdr *cap, const unsigned char *data)
312 NetVis *self = reinterpret_cast<NetVis *>(user);
316 const ethhdr *eth = reinterpret_cast<const ethhdr *>(data);
317 self->handle_ethernet(ctx, eth, cap->caplen);
320 void NetVis::handle_ethernet(CaptureContext &ctx, const ethhdr *eth, unsigned len)
322 ctx.size = ctx.cap_hdr->len-sizeof(ethhdr);
324 int proto = ntohs(eth->h_proto);
327 const iphdr *ip = reinterpret_cast<const iphdr *>(eth+1);
328 handle_ipv4(ctx, ip, len-sizeof(ethhdr));
330 else if(proto==ETH_P_IPV6)
332 const ip6_hdr *ip6 = reinterpret_cast<const ip6_hdr *>(eth+1);
333 handle_ipv6(ctx, ip6, len-sizeof(ethhdr));
336 IO::print("Unknown protocol in eth: %d\n", proto);
339 void NetVis::handle_ipv4(CaptureContext &ctx, const iphdr *ip, unsigned len)
341 ctx.src_host = &get_host(ntohl(ip->saddr));
342 if((ntohl(ip->daddr)&0xFF)!=0xFF)
343 ctx.dst_host = &get_host(ntohl(ip->daddr));
345 if(ip->protocol==IPPROTO_TCP)
347 const tcphdr *tcp = reinterpret_cast<const tcphdr *>(ip+1);
348 handle_tcp(ctx, tcp, len-sizeof(iphdr));
350 else if(ip->protocol==IPPROTO_UDP)
352 const udphdr *udp = reinterpret_cast<const udphdr *>(ip+1);
353 handle_udp(ctx, udp, len-sizeof(iphdr));
355 else if(ip->protocol==IPPROTO_ICMP)
357 const icmphdr *icmp = reinterpret_cast<const icmphdr *>(ip+1);
358 handle_icmp(ctx, icmp, len-sizeof(iphdr));
361 IO::print("Unknown protocol in ip: %d\n", ip->protocol);
364 void NetVis::handle_ipv6(CaptureContext &ctx, const ip6_hdr *ip6, unsigned len)
366 ctx.src_host = &get_host(ip6->ip6_src);
367 if(!IN6_IS_ADDR_MULTICAST(ip6->ip6_dst.s6_addr))
368 ctx.dst_host = &get_host(ip6->ip6_dst);
370 if(ip6->ip6_nxt==IPPROTO_TCP)
372 const tcphdr *tcp = reinterpret_cast<const tcphdr *>(ip6+1);
373 handle_tcp(ctx, tcp, len-sizeof(ip6_hdr));
375 else if(ip6->ip6_nxt==IPPROTO_UDP)
377 const udphdr *udp = reinterpret_cast<const udphdr *>(ip6+1);
378 handle_udp(ctx, udp, len-sizeof(ip6_hdr));
380 else if(ip6->ip6_nxt==IPPROTO_ICMPV6)
382 const icmp6_hdr *icmp6 = reinterpret_cast<const icmp6_hdr *>(ip6+1);
383 handle_icmp6(ctx, icmp6, len-sizeof(ip6_hdr));
386 IO::print("Unknown next header in ip6: %d\n", ip6->ip6_nxt);
389 void NetVis::handle_tcp(CaptureContext &ctx, const tcphdr *tcp, unsigned)
391 ctx.src_port = &get_port(ntohs(tcp->source));
392 ctx.dst_port = &get_port(ntohs(tcp->dest));
396 void NetVis::handle_udp(CaptureContext &ctx, const udphdr *udp, unsigned)
398 ctx.src_port = &get_port(ntohs(udp->source));
399 ctx.dst_port = &get_port(ntohs(udp->dest));
403 void NetVis::handle_icmp(CaptureContext &ctx, const icmphdr *, unsigned)
405 ctx.src_port = &get_port(0x10000|IPPROTO_ICMP);
406 ctx.dst_port = ctx.src_port;
410 void NetVis::handle_icmp6(CaptureContext &ctx, const icmp6_hdr *, unsigned)
412 ctx.src_port = &get_port(0x10000|IPPROTO_ICMPV6);
413 ctx.dst_port = ctx.src_port;
417 void NetVis::handle_packet(CaptureContext &ctx)
420 if(ctx.src_port && ctx.dst_port)
422 if(ctx.src_port->is_registered()!=ctx.dst_port->is_registered())
424 if(ctx.src_port->is_registered())
429 else if(ctx.src_port->get_number()<ctx.dst_port->get_number())
437 float throttle = ctx.src_host->send_packet();
440 packets.push_back(new Packet(*ctx.src_host, ctx.dst_host, port->get_color(), ctx.size));
441 packets.back()->tick(-throttle*Msp::Time::sec);
444 ctx.src_host->add_activity(ctx.size);
446 ctx.dst_host->add_activity(ctx.size);
449 ctx.src_port->add_activity(ctx.size);
451 ctx.dst_port->add_activity(ctx.size);
453 bool local_src = ctx.src_host->is_local();
454 bool local_dst = (ctx.dst_host && ctx.dst_host->is_local());
455 if(local_src && !local_dst)
456 history->activity(0, ctx.size);
457 else if(local_dst && !local_src)
458 history->activity(ctx.size, 0);
461 void NetVis::sighandler(int)
467 NetVis::CaptureContext::CaptureContext():