Branch data Line data Source code
1 : : // $Id: Sessions.cc 7075 2010-09-13 02:39:38Z vern $
2 : : //
3 : : // See the file "COPYING" in the main distribution directory for copyright.
4 : :
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <arpa/inet.h>
9 : :
10 : : #include <stdlib.h>
11 : : #include <unistd.h>
12 : :
13 : : #include "Net.h"
14 : : #include "Event.h"
15 : : #include "Timer.h"
16 : : #include "NetVar.h"
17 : : #include "Sessions.h"
18 : : #include "Active.h"
19 : : #include "OSFinger.h"
20 : :
21 : : #include "ICMP.h"
22 : : #include "UDP.h"
23 : :
24 : : #include "DNS-binpac.h"
25 : : #include "HTTP-binpac.h"
26 : :
27 : : #include "SteppingStone.h"
28 : : #include "BackDoor.h"
29 : : #include "InterConn.h"
30 : : #include "Discard.h"
31 : : #include "RuleMatcher.h"
32 : : #include "ConnCompressor.h"
33 : : #include "DPM.h"
34 : :
35 : : #include "PacketSort.h"
36 : :
37 : : // These represent NetBIOS services on ephemeral ports. They're numbered
38 : : // so that we can use a single int to hold either an actual TCP/UDP server
39 : : // port or one of these.
40 : : enum NetBIOS_Service {
41 : : NETBIOS_SERVICE_START = 0x10000L, // larger than any port
42 : : NETBIOS_SERVICE_DCE_RPC,
43 : : };
44 : :
45 : : NetSessions* sessions;
46 : :
47 : :
48 [ # # ][ # # ]: 0 : class NetworkTimer : public Timer {
49 : : public:
50 : 0 : NetworkTimer(NetSessions* arg_sess, double arg_t)
51 : 0 : : Timer(arg_t, TIMER_NETWORK)
52 : 0 : { sess = arg_sess; }
53 : :
54 : : void Dispatch(double t, int is_expire);
55 : :
56 : : protected:
57 : : NetSessions* sess;
58 : : };
59 : :
60 : 0 : void NetworkTimer::Dispatch(double t, int is_expire)
61 : : {
62 [ # # ]: 0 : if ( is_expire )
63 : 0 : return;
64 : :
65 : 0 : sess->HeartBeat(t);
66 : : }
67 : :
68 : 0 : void TimerMgrExpireTimer::Dispatch(double t, int is_expire)
69 : : {
70 [ # # ]: 0 : if ( mgr->LastAdvance() + timer_mgr_inactivity_timeout < timer_mgr->Time() )
71 : : {
72 : : // Expired.
73 : 0 : DBG_LOG(DBG_TM, "TimeMgr %p has timed out", mgr);
74 : 0 : mgr->Expire();
75 : :
76 : : // Make sure events are executed. They depend on the TimerMgr.
77 : 0 : ::mgr.Drain();
78 : :
79 : 0 : sessions->timer_mgrs.erase(mgr->GetTag());
80 [ # # ]: 0 : delete mgr;
81 : : }
82 : : else
83 : : {
84 : : // Reinstall timer.
85 [ # # ]: 0 : if ( ! is_expire )
86 : : {
87 : : double n = mgr->LastAdvance() +
88 : 0 : timer_mgr_inactivity_timeout;
89 : 0 : timer_mgr->Add(new TimerMgrExpireTimer(n, mgr));
90 : : }
91 : : }
92 : 0 : }
93 : :
94 : 1 : NetSessions::NetSessions()
95 : : {
96 : 1 : TypeList* t = new TypeList();
97 : 1 : t->Append(base_type(TYPE_COUNT)); // source IP address
98 : 1 : t->Append(base_type(TYPE_COUNT)); // dest IP address
99 : 1 : t->Append(base_type(TYPE_COUNT)); // source and dest ports
100 : :
101 : 1 : ch = new CompositeHash(t);
102 : :
103 : 1 : Unref(t);
104 : :
105 : 1 : tcp_conns.SetDeleteFunc(bro_obj_delete_func);
106 : 1 : udp_conns.SetDeleteFunc(bro_obj_delete_func);
107 : 1 : fragments.SetDeleteFunc(bro_obj_delete_func);
108 : :
109 [ + - - + ]: 1 : if ( (reading_live || pseudo_realtime) && net_stats_update )
[ # # ]
[ - + # # ]
[ # # ][ # # ]
[ # # ]
110 : 0 : timer_mgr->Add(new NetworkTimer(this, 1.0));
111 : :
112 [ - + ][ # # ]: 1 : if ( stp_correlate_pair )
113 : 0 : stp_manager = new SteppingStoneManager();
114 : : else
115 : 1 : stp_manager = 0;
116 : :
117 : 1 : discarder = new Discarder();
118 [ + - # # ]: 1 : if ( ! discarder->IsActive() )
119 : : {
120 [ + - ][ # # ]: 1 : delete discarder;
121 : 1 : discarder = 0;
122 : : }
123 : :
124 : 1 : packet_filter = 0;
125 : :
126 : : build_backdoor_analyzer =
127 : : backdoor_stats || rlogin_signature_found ||
128 : : telnet_signature_found || ssh_signature_found ||
129 : : root_backdoor_signature_found || ftp_signature_found ||
130 : : napster_signature_found || kazaa_signature_found ||
131 [ + - ][ + - ]: 1 : http_signature_found || http_proxy_signature_found;
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ - + ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
132 : :
133 : 1 : dump_this_packet = 0;
134 : 1 : num_packets_processed = 0;
135 : :
136 [ - + ][ # # ]: 1 : if ( OS_version_found )
137 : : {
138 : 0 : SYN_OS_Fingerprinter = new OSFingerprint(SYN_FINGERPRINT_MODE);
139 [ # # # # ]: 0 : if ( SYN_OS_Fingerprinter->Error() )
140 : 0 : exit(1);
141 : : }
142 : : else
143 : 1 : SYN_OS_Fingerprinter = 0;
144 : :
145 [ - + ][ # # ]: 1 : if ( pkt_profile_mode && pkt_profile_freq > 0 && pkt_profile_file )
[ # # ][ # # ]
[ # # ][ # # ]
146 : : pkt_profiler = new PacketProfiler(pkt_profile_mode,
147 : 0 : pkt_profile_freq, pkt_profile_file->AsFile());
148 : : else
149 : 1 : pkt_profiler = 0;
150 : :
151 [ + - ][ + - ]: 1 : if ( arp_request || arp_reply || bad_arp )
[ - + ][ - + ]
[ # # ][ # # ]
[ # # ][ # # ]
152 : 0 : arp_analyzer = new ARP_Analyzer();
153 : : else
154 : 1 : arp_analyzer = 0;
155 : 1 : }
156 : :
157 : 1 : NetSessions::~NetSessions()
158 : : {
159 [ + - ][ # # ]: 1 : delete ch;
160 [ - + ][ # # ]: 1 : delete packet_filter;
161 [ - + ][ # # ]: 1 : delete SYN_OS_Fingerprinter;
162 [ - + ][ # # ]: 1 : delete pkt_profiler;
163 : 1 : Unref(arp_analyzer);
164 : 1 : }
165 : :
166 : 1 : void NetSessions::Done()
167 : : {
168 [ - + ]: 1 : delete stp_manager;
169 [ - + ]: 1 : delete discarder;
170 : 1 : }
171 : :
172 : : namespace // private namespace
173 : : {
174 : 0 : bool looks_like_IPv4_packet(int len, const struct ip* ip_hdr)
175 : : {
176 [ # # ]: 0 : if ( len < int(sizeof(struct ip)) )
177 : 0 : return false;
178 [ # # ][ # # ]: 0 : return ip_hdr->ip_v == 4 && ntohs(ip_hdr->ip_len) == len;
179 : : }
180 : : }
181 : :
182 : : void NetSessions::DispatchPacket(double t, const struct pcap_pkthdr* hdr,
183 : : const u_char* pkt, int hdr_size,
184 : 21347 : PktSrc* src_ps, PacketSortElement* pkt_elem)
185 : : {
186 : 21347 : const struct ip* ip_hdr = 0;
187 : 21347 : const u_char* ip_data = 0;
188 : 21347 : int proto = 0;
189 : :
190 [ + - ]: 21347 : if ( hdr->caplen >= hdr_size + sizeof(struct ip) )
191 : : {
192 : 21347 : ip_hdr = reinterpret_cast<const struct ip*>(pkt + hdr_size);
193 [ + - ]: 21347 : if ( hdr->caplen >= unsigned(hdr_size + (ip_hdr->ip_hl << 2)) )
194 : 21347 : ip_data = pkt + hdr_size + (ip_hdr->ip_hl << 2);
195 : : }
196 : :
197 [ - + ][ # # ]: 21347 : if ( encap_hdr_size > 0 && ip_data )
198 : : {
199 : : // We're doing tunnel encapsulation. Check whether there's
200 : : // a particular associated port.
201 : : //
202 : : // Should we discourage the use of encap_hdr_size for UDP
203 : : // tunnneling? It is probably better handled by enabling
204 : : // parse_udp_tunnels instead of specifying a fixed
205 : : // encap_hdr_size.
206 [ # # ]: 0 : if ( udp_tunnel_port > 0 )
207 : : {
208 [ # # ]: 0 : ASSERT(ip_hdr);
209 [ # # ]: 0 : if ( ip_hdr->ip_p == IPPROTO_UDP )
210 : : {
211 : : const struct udphdr* udp_hdr =
212 : : reinterpret_cast<const struct udphdr*>
213 : 0 : (ip_data);
214 : :
215 [ # # ]: 0 : if ( ntohs(udp_hdr->uh_dport) == udp_tunnel_port )
216 : : {
217 : : // A match.
218 : 0 : hdr_size += encap_hdr_size;
219 : : }
220 : : }
221 : : }
222 : :
223 : : else
224 : : // Blanket encapsulation (e.g., for VLAN).
225 : 0 : hdr_size += encap_hdr_size;
226 : : }
227 : :
228 : : // Check IP packets encapsulated through UDP tunnels.
229 : : // Specifying a udp_tunnel_port is optional but recommended (to avoid
230 : : // the cost of checking every UDP packet).
231 [ - + ][ # # ]: 21347 : else if ( parse_udp_tunnels && ip_data && ip_hdr->ip_p == IPPROTO_UDP )
[ # # ]
232 : : {
233 : : const struct udphdr* udp_hdr =
234 : 0 : reinterpret_cast<const struct udphdr*>(ip_data);
235 : :
236 [ # # ][ # # ]: 0 : if ( udp_tunnel_port == 0 || // 0 matches any port
[ # # ]
237 : : udp_tunnel_port == ntohs(udp_hdr->uh_dport) )
238 : : {
239 : : const u_char* udp_data =
240 : 0 : ip_data + sizeof(struct udphdr);
241 : : const struct ip* ip_encap =
242 : 0 : reinterpret_cast<const struct ip*>(udp_data);
243 : : const int ip_encap_len =
244 : 0 : ntohs(udp_hdr->uh_ulen) - sizeof(struct udphdr);
245 : : const int ip_encap_caplen =
246 : 0 : hdr->caplen - (udp_data - pkt);
247 : :
248 [ # # ]: 0 : if ( looks_like_IPv4_packet(ip_encap_len, ip_encap) )
249 : 0 : hdr_size = udp_data - pkt;
250 : : }
251 : : }
252 : :
253 [ + - ]: 21347 : if ( src_ps->FilterType() == TYPE_FILTER_NORMAL )
254 : 21347 : NextPacket(t, hdr, pkt, hdr_size, pkt_elem);
255 : : else
256 : 0 : NextPacketSecondary(t, hdr, pkt, hdr_size, src_ps);
257 : 21347 : }
258 : :
259 : : void NetSessions::NextPacket(double t, const struct pcap_pkthdr* hdr,
260 : : const u_char* const pkt, int hdr_size,
261 : 21347 : PacketSortElement* pkt_elem)
262 : : {
263 : 21347 : SegmentProfiler(segment_logger, "processing-packet");
264 [ - + ]: 21347 : if ( pkt_profiler )
265 : 0 : pkt_profiler->ProfilePkt(t, hdr->caplen);
266 : :
267 : 21347 : ++num_packets_processed;
268 : :
269 : 21347 : dump_this_packet = 0;
270 : :
271 [ - + ]: 21347 : if ( record_all_packets )
272 : 0 : DumpPacket(hdr, pkt);
273 : :
274 [ - + ][ # # ]: 21347 : if ( pkt_elem && pkt_elem->IPHdr() )
[ - + ]
275 : : // Fast path for "normal" IP packets if an IP_Hdr is
276 : : // already extracted when doing PacketSort. Otherwise
277 : : // the code below tries to extract the IP header, the
278 : : // difference here is that header extraction in
279 : : // PacketSort does not generate Weird events.
280 : :
281 : 0 : DoNextPacket(t, hdr, pkt_elem->IPHdr(), pkt, hdr_size);
282 : :
283 : : else
284 : : {
285 : : // ### The following isn't really correct. What we *should*
286 : : // do is understanding the different link layers in order to
287 : : // find the network-layer protocol ID. That's a big
288 : : // portability pain, though, unless we just assume everything's
289 : : // Ethernet .... not great, given the potential need to deal
290 : : // with PPP or FDDI (for some older traces). So instead
291 : : // we look to see if what we have is consistent with an
292 : : // IPv4 packet. If not, it's either ARP or IPv6 or weird.
293 : :
294 : 21347 : uint32 caplen = hdr->caplen - hdr_size;
295 [ - + ]: 21347 : if ( caplen < sizeof(struct ip) )
296 : : {
297 : 0 : Weird("truncated_IP", hdr, pkt);
298 : 0 : return;
299 : : }
300 : :
301 : 21347 : const struct ip* ip = (const struct ip*) (pkt + hdr_size);
302 [ + + ]: 21347 : if ( ip->ip_v == 4 )
303 : : {
304 : 20378 : IP_Hdr ip_hdr(ip);
305 : 20378 : DoNextPacket(t, hdr, &ip_hdr, pkt, hdr_size);
306 : : }
307 : :
308 [ - + ][ # # ]: 969 : else if ( arp_analyzer && arp_analyzer->IsARP(pkt, hdr_size) )
[ - + ]
309 : 0 : arp_analyzer->NextPacket(t, hdr, pkt, hdr_size);
310 : :
311 : : else
312 : : {
313 : : #ifdef BROv6
314 : : IP_Hdr ip_hdr((const struct ip6_hdr*) (pkt + hdr_size));
315 : : DoNextPacket(t, hdr, &ip_hdr, pkt, hdr_size);
316 : : #else
317 : 969 : Weird("non_IPv4_packet", hdr, pkt);
318 : 969 : return;
319 : : #endif
320 : : }
321 : : }
322 : :
323 [ + + ][ + - ]: 20378 : if ( dump_this_packet && ! record_all_packets )
324 : 21347 : DumpPacket(hdr, pkt);
325 : : }
326 : :
327 : : void NetSessions::NextPacketSecondary(double /* t */, const struct pcap_pkthdr* hdr,
328 : : const u_char* const pkt, int hdr_size,
329 : 0 : const PktSrc* src_ps)
330 : : {
331 : 0 : SegmentProfiler(segment_logger, "processing-secondary-packet");
332 : :
333 : 0 : ++num_packets_processed;
334 : :
335 : 0 : uint32 caplen = hdr->caplen - hdr_size;
336 [ # # ]: 0 : if ( caplen < sizeof(struct ip) )
337 : : {
338 : 0 : Weird("truncated_IP", hdr, pkt);
339 : 0 : return;
340 : : }
341 : :
342 : 0 : const struct ip* ip = (const struct ip*) (pkt + hdr_size);
343 [ # # ]: 0 : if ( ip->ip_v == 4 )
344 : : {
345 : 0 : const secondary_program_list& spt = src_ps->ProgramTable();
346 : :
347 [ # # ]: 0 : loop_over_list(spt, i)
348 : : {
349 : 0 : SecondaryProgram* sp = spt[i];
350 [ # # ]: 0 : if ( ! net_packet_match(sp->Program(), pkt,
351 : : hdr->len, hdr->caplen) )
352 : 0 : continue;
353 : :
354 : 0 : val_list* args = new val_list;
355 : : StringVal* cmd_val =
356 : 0 : new StringVal(sp->Event()->Filter());
357 : 0 : args->append(cmd_val);
358 : 0 : args->append(BuildHeader(ip));
359 : : // ### Need to queue event here.
360 : 0 : sp->Event()->Event()->Call(args);
361 [ # # ]: 0 : delete args;
362 : : }
363 : : }
364 : : }
365 : :
366 : 1025 : int NetSessions::CheckConnectionTag(Connection* conn)
367 : : {
368 [ - + ]: 1025 : if ( current_iosrc->GetCurrentTag() )
369 : : {
370 : : // Packet is tagged.
371 [ # # ]: 0 : if ( conn->GetTimerMgr() == timer_mgr )
372 : : {
373 : : // Connection uses global timer queue. But the
374 : : // packet has a tag that means we got it externally,
375 : : // probably from the Time Machine.
376 : 0 : DBG_LOG(DBG_TM, "got packet with tag %s for already"
377 : : "known connection, reinstantiating",
378 : : current_iosrc->GetCurrentTag()->c_str());
379 : 0 : return 0;
380 : : }
381 : : else
382 : : {
383 : : // Connection uses local timer queue.
384 : : TimerMgrMap::iterator i =
385 : 0 : timer_mgrs.find(*current_iosrc->GetCurrentTag());
386 [ # # # # ]: 0 : if ( i != timer_mgrs.end() &&
[ # # ]
387 : : conn->GetTimerMgr() != i->second )
388 : : {
389 : : // Connection uses different local queue
390 : : // than the tag for the current packet
391 : : // indicates.
392 : : //
393 : : // This can happen due to:
394 : : // (1) getting same packets with
395 : : // different tags
396 : : // (2) timer mgr having already expired
397 : 0 : DBG_LOG(DBG_TM, "packet ignored due old/inconsistent tag");
398 : 0 : return -1;
399 : : }
400 : :
401 : 0 : return 1;
402 : : }
403 : : }
404 : :
405 : : // Packet is not tagged.
406 [ - + ]: 1025 : if ( conn->GetTimerMgr() != timer_mgr )
407 : : {
408 : : // Connection does not use the global timer queue. That
409 : : // means that this is a live packet belonging to a
410 : : // connection for which we have already switched to
411 : : // processing external input.
412 : 0 : DBG_LOG(DBG_TM, "packet ignored due to processing it in external data");
413 : 0 : return -1;
414 : : }
415 : :
416 : 1025 : return 1;
417 : : }
418 : :
419 : :
420 : 0 : static bool looks_like_IPv4_packet(int len, const struct ip* ip_hdr)
421 : : {
422 [ # # ]: 0 : if ( (unsigned int) len < sizeof(struct ip) )
423 : 0 : return false;
424 : :
425 [ # # ][ # # ]: 0 : if ( ip_hdr->ip_v == 4 && ntohs(ip_hdr->ip_len) == len )
[ # # ]
426 : 0 : return true;
427 : : else
428 : 0 : return false;
429 : : }
430 : :
431 : : void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
432 : : const IP_Hdr* ip_hdr, const u_char* const pkt,
433 : 20378 : int hdr_size)
434 : : {
435 : 20378 : uint32 caplen = hdr->caplen - hdr_size;
436 : 20378 : const struct ip* ip4 = ip_hdr->IP4_Hdr();
437 : :
438 : 20378 : uint32 len = ip_hdr->TotalLen();
439 [ - + ]: 20378 : if ( hdr->len < len + hdr_size )
440 : : {
441 : 0 : Weird("truncated_IP", hdr, pkt);
442 : 0 : return;
443 : : }
444 : :
445 : : // Ignore if packet matches packet filter.
446 [ - + ][ # # ]: 20378 : if ( packet_filter && packet_filter->Match(ip_hdr, len, caplen) )
[ - + ]
447 : 0 : return;
448 : :
449 : 20378 : int ip_hdr_len = ip_hdr->HdrLen();
450 [ + - + - ]: 20378 : if ( ! ignore_checksums && ip4 &&
[ - + ][ - + ]
451 : : ones_complement_checksum((void*) ip4, ip_hdr_len, 0) != 0xffff )
452 : : {
453 : 0 : Weird("bad_IP_checksum", hdr, pkt);
454 : 0 : return;
455 : : }
456 : :
457 [ - + ][ # # ]: 20378 : if ( discarder && discarder->NextPacket(ip_hdr, len, caplen) )
[ - + ]
458 : 0 : return;
459 : :
460 : 20378 : int proto = ip_hdr->NextProto();
461 [ + + + + ]: 20378 : if ( proto != IPPROTO_TCP && proto != IPPROTO_UDP &&
[ + + ]
462 : : proto != IPPROTO_ICMP )
463 : : {
464 : 108 : dump_this_packet = 1;
465 : 108 : return;
466 : : }
467 : :
468 : : // Check for TTL/MTU problems from Active Mapping
469 : : #ifdef ACTIVE_MAPPING
470 : : const NumericData* numeric = 0;
471 : : if ( ip4 )
472 : : {
473 : : get_map_result(ip4->ip_dst.s_addr, numeric);
474 : :
475 : : if ( numeric->hops && ip4->ip_ttl < numeric->hops )
476 : : {
477 : : debug_msg("Packet destined for %s had ttl %d but there are %d hops to host.\n",
478 : : inet_ntoa(ip4->ip_dst), ip4->ip_ttl, numeric->hops);
479 : : return;
480 : : }
481 : : }
482 : : #endif
483 : :
484 : 20270 : FragReassembler* f = 0;
485 : 20270 : uint32 frag_field = ip_hdr->FragField();
486 : :
487 : : #ifdef ACTIVE_MAPPING
488 : : if ( ip4 && numeric && numeric->path_MTU && (frag_field & IP_DF) )
489 : : {
490 : : if ( htons(ip4->ip_len) > numeric->path_MTU )
491 : : {
492 : : debug_msg("Packet destined for %s has DF flag but its size %d is greater than pmtu of %d\n",
493 : : inet_ntoa(ip4->ip_dst), htons(ip4->ip_len), numeric->path_MTU);
494 : : return;
495 : : }
496 : : }
497 : : #endif
498 : :
499 [ - + ]: 20270 : if ( (frag_field & 0x3fff) != 0 )
500 : : {
501 : 0 : dump_this_packet = 1; // always record fragments
502 : :
503 [ # # ]: 0 : if ( caplen < len )
504 : : {
505 : 0 : Weird("incompletely_captured_fragment", ip_hdr);
506 : :
507 : : // Don't try to reassemble, that's doomed.
508 : : // Discard all except the first fragment (which
509 : : // is useful in analyzing header-only traces)
510 [ # # ]: 0 : if ( (frag_field & 0x1fff) != 0 )
511 : 0 : return;
512 : : }
513 : : else
514 : : {
515 : 0 : f = NextFragment(t, ip_hdr, pkt + hdr_size, frag_field);
516 : 0 : const IP_Hdr* ih = f->ReassembledPkt();
517 [ # # ]: 0 : if ( ! ih )
518 : : // It didn't reassemble into anything yet.
519 : 0 : return;
520 : :
521 : 0 : ip4 = ih->IP4_Hdr();
522 : 0 : ip_hdr = ih;
523 : :
524 : 0 : caplen = len = ip_hdr->TotalLen();
525 : 0 : ip_hdr_len = ip_hdr->HdrLen();
526 : : }
527 : : }
528 : :
529 : 20270 : len -= ip_hdr_len; // remove IP header
530 : 20270 : caplen -= ip_hdr_len;
531 : :
532 : : uint32 min_hdr_len = (proto == IPPROTO_TCP) ? sizeof(struct tcphdr) :
533 [ + + ]: 20270 : (proto == IPPROTO_UDP ? sizeof(struct udphdr) : ICMP_MINLEN);
534 : :
535 [ - + ]: 20270 : if ( len < min_hdr_len )
536 : : {
537 : 0 : Weird("truncated_header", hdr, pkt);
538 [ # # ]: 0 : if ( f )
539 : 0 : Remove(f); // ###
540 : 0 : return;
541 : : }
542 [ - + ]: 20270 : if ( caplen < min_hdr_len )
543 : : {
544 : 0 : Weird("internally_truncated_header", hdr, pkt);
545 [ # # ]: 0 : if ( f )
546 : 0 : Remove(f); // ###
547 : 0 : return;
548 : : }
549 : :
550 : 20270 : const u_char* data = ip_hdr->Payload();
551 : :
552 : : ConnID id;
553 : 20270 : id.src_addr = ip_hdr->SrcAddr();
554 : 20270 : id.dst_addr = ip_hdr->DstAddr();
555 : 20270 : Dictionary* d = 0;
556 : 20270 : bool pass_to_conn_compressor = false;
557 : :
558 [ + + + - ]: 20270 : switch ( proto ) {
559 : : case IPPROTO_TCP:
560 : : {
561 : 18556 : const struct tcphdr* tp = (const struct tcphdr *) data;
562 : 18556 : id.src_port = tp->th_sport;
563 : 18556 : id.dst_port = tp->th_dport;
564 : 18556 : id.is_one_way = 0;
565 : 18556 : d = &tcp_conns;
566 [ + - ][ + - ]: 18556 : pass_to_conn_compressor = ip4 && use_connection_compressor;
567 : 18556 : break;
568 : : }
569 : :
570 : : case IPPROTO_UDP:
571 : : {
572 : 1683 : const struct udphdr* up = (const struct udphdr *) data;
573 : 1683 : id.src_port = up->uh_sport;
574 : 1683 : id.dst_port = up->uh_dport;
575 : 1683 : id.is_one_way = 0;
576 : 1683 : d = &udp_conns;
577 : 1683 : break;
578 : : }
579 : :
580 : : case IPPROTO_ICMP:
581 : : {
582 : 31 : const struct icmp* icmpp = (const struct icmp *) data;
583 : :
584 : 31 : id.src_port = icmpp->icmp_type;
585 : : id.dst_port = ICMP_counterpart(icmpp->icmp_type,
586 : : icmpp->icmp_code,
587 : 31 : id.is_one_way);
588 : :
589 : 31 : id.src_port = htons(id.src_port);
590 : 31 : id.dst_port = htons(id.dst_port);
591 : :
592 : 31 : d = &icmp_conns;
593 : 31 : break;
594 : : }
595 : :
596 : : default:
597 : 0 : Weird(fmt("unknown_protocol %d", proto), hdr, pkt);
598 : 0 : return;
599 : : }
600 : :
601 : 20270 : HashKey* h = id.BuildConnKey();
602 [ - + ]: 20270 : if ( ! h )
603 : 0 : internal_error("hash computation failed");
604 : :
605 : 20270 : Connection* conn = 0;
606 : :
607 : : // FIXME: The following is getting pretty complex. Need to split up
608 : : // into separate functions.
609 [ + + ]: 20270 : if ( pass_to_conn_compressor )
610 : 18556 : conn = conn_compressor->NextPacket(t, h, ip_hdr, hdr, pkt);
611 : : else
612 : : {
613 : 1714 : conn = (Connection*) d->Lookup(h);
614 [ + + ]: 1714 : if ( ! conn )
615 : : {
616 : 689 : conn = NewConn(h, t, &id, data, proto);
617 [ + - ]: 689 : if ( conn )
618 : 689 : d->Insert(h, conn);
619 : : }
620 : : else
621 : : {
622 : : // We already know that connection.
623 : 1025 : int consistent = CheckConnectionTag(conn);
624 [ - + ]: 1025 : if ( consistent < 0 )
625 : : {
626 [ # # ]: 0 : delete h;
627 : 0 : return;
628 : : }
629 : :
630 [ + - ][ - + ]: 1025 : if ( ! consistent || conn->IsReuse(t, data) )
[ - + ]
631 : : {
632 [ # # ]: 0 : if ( consistent )
633 : 0 : conn->Event(connection_reused, 0);
634 : :
635 : 0 : Remove(conn);
636 : 0 : conn = NewConn(h, t, &id, data, proto);
637 [ # # ]: 0 : if ( conn )
638 : 0 : d->Insert(h, conn);
639 : : }
640 : : else
641 [ + - ]: 1025 : delete h;
642 : : }
643 : :
644 [ - + ]: 1714 : if ( ! conn )
645 [ # # ]: 0 : delete h;
646 : : }
647 : :
648 [ + + ]: 20270 : if ( ! conn )
649 : 1104 : return;
650 : :
651 : 19166 : int record_packet = 1; // whether to record the packet at all
652 : 19166 : int record_content = 1; // whether to record its data
653 : :
654 : : int is_orig = addr_eq(id.src_addr, conn->OrigAddr()) &&
655 [ + + ][ + - ]: 19166 : id.src_port == conn->OrigPort();
656 : :
657 [ - + ][ # # ]: 19166 : if ( new_packet && ip4 )
[ - + ]
658 : 0 : conn->Event(new_packet, 0, BuildHeader(ip4));
659 : :
660 : : conn->NextPacket(t, is_orig, ip_hdr, len, caplen, data,
661 : : record_packet, record_content,
662 : 19166 : hdr, pkt, hdr_size);
663 : :
664 : : // Override content record setting according to
665 : : // flags set by the policy script.
666 [ - + ]: 19166 : if ( dump_original_packets_if_not_rewriting )
667 : 0 : record_packet = record_content = 1;
668 [ - + ]: 19166 : if ( dump_selected_source_packets )
669 : 0 : record_packet = record_content = 0;
670 : :
671 [ - + ]: 19166 : if ( f )
672 : : {
673 : : // Above we already recorded the fragment in its entirety.
674 : 0 : f->DeleteTimer();
675 : 0 : Remove(f); // ###
676 : : }
677 : :
678 [ + - ][ + - ]: 19166 : else if ( record_packet && ! conn->RewritingTrace() )
[ + - ]
679 : : {
680 [ + - ]: 19166 : if ( record_content )
681 : 19166 : dump_this_packet = 1; // save the whole thing
682 : :
683 : : else
684 : : {
685 : 0 : int hdr_len = data - pkt;
686 : 20378 : DumpPacket(hdr, pkt, hdr_len); // just save the header
687 : : }
688 : : }
689 : : }
690 : :
691 : 0 : Val* NetSessions::BuildHeader(const struct ip* ip)
692 : : {
693 : : static RecordType* pkt_hdr_type = 0;
694 : : static RecordType* ip_hdr_type = 0;
695 : : static RecordType* tcp_hdr_type = 0;
696 : : static RecordType* udp_hdr_type = 0;
697 : : static RecordType* icmp_hdr_type;
698 : :
699 [ # # ]: 0 : if ( ! pkt_hdr_type )
700 : : {
701 : 0 : pkt_hdr_type = internal_type("pkt_hdr")->AsRecordType();
702 : 0 : ip_hdr_type = internal_type("ip_hdr")->AsRecordType();
703 : 0 : tcp_hdr_type = internal_type("tcp_hdr")->AsRecordType();
704 : 0 : udp_hdr_type = internal_type("udp_hdr")->AsRecordType();
705 : 0 : icmp_hdr_type = internal_type("icmp_hdr")->AsRecordType();
706 : : }
707 : :
708 : 0 : RecordVal* pkt_hdr = new RecordVal(pkt_hdr_type);
709 : :
710 : 0 : RecordVal* ip_hdr = new RecordVal(ip_hdr_type);
711 : :
712 : 0 : int ip_hdr_len = ip->ip_hl * 4;
713 : 0 : int ip_pkt_len = ntohs(ip->ip_len);
714 : :
715 : 0 : ip_hdr->Assign(0, new Val(ip->ip_hl * 4, TYPE_COUNT));
716 : 0 : ip_hdr->Assign(1, new Val(ip->ip_tos, TYPE_COUNT));
717 : 0 : ip_hdr->Assign(2, new Val(ip_pkt_len, TYPE_COUNT));
718 : 0 : ip_hdr->Assign(3, new Val(ntohs(ip->ip_id), TYPE_COUNT));
719 : 0 : ip_hdr->Assign(4, new Val(ip->ip_ttl, TYPE_COUNT));
720 : 0 : ip_hdr->Assign(5, new Val(ip->ip_p, TYPE_COUNT));
721 : 0 : ip_hdr->Assign(6, new AddrVal(ip->ip_src.s_addr));
722 : 0 : ip_hdr->Assign(7, new AddrVal(ip->ip_dst.s_addr));
723 : :
724 : 0 : pkt_hdr->Assign(0, ip_hdr);
725 : :
726 : : // L4 header.
727 : 0 : const u_char* data = ((const u_char*) ip) + ip_hdr_len;
728 : :
729 : 0 : int proto = ip->ip_p;
730 [ # # # # ]: 0 : switch ( proto ) {
731 : : case IPPROTO_TCP:
732 : : {
733 : 0 : const struct tcphdr* tp = (const struct tcphdr*) data;
734 : 0 : RecordVal* tcp_hdr = new RecordVal(tcp_hdr_type);
735 : :
736 : 0 : int tcp_hdr_len = tp->th_off * 4;
737 : 0 : int data_len = ip_pkt_len - ip_hdr_len - tcp_hdr_len;
738 : :
739 : 0 : tcp_hdr->Assign(0, new PortVal(ntohs(tp->th_sport), TRANSPORT_TCP));
740 : 0 : tcp_hdr->Assign(1, new PortVal(ntohs(tp->th_dport), TRANSPORT_TCP));
741 : 0 : tcp_hdr->Assign(2, new Val(uint32(ntohl(tp->th_seq)), TYPE_COUNT));
742 : 0 : tcp_hdr->Assign(3, new Val(uint32(ntohl(tp->th_ack)), TYPE_COUNT));
743 : 0 : tcp_hdr->Assign(4, new Val(tcp_hdr_len, TYPE_COUNT));
744 : 0 : tcp_hdr->Assign(5, new Val(data_len, TYPE_COUNT));
745 : 0 : tcp_hdr->Assign(6, new Val(tp->th_flags, TYPE_COUNT));
746 : 0 : tcp_hdr->Assign(7, new Val(ntohs(tp->th_win), TYPE_COUNT));
747 : :
748 : 0 : pkt_hdr->Assign(1, tcp_hdr);
749 : 0 : break;
750 : : }
751 : :
752 : : case IPPROTO_UDP:
753 : : {
754 : 0 : const struct udphdr* up = (const struct udphdr*) data;
755 : 0 : RecordVal* udp_hdr = new RecordVal(udp_hdr_type);
756 : :
757 : 0 : udp_hdr->Assign(0, new PortVal(ntohs(up->uh_sport), TRANSPORT_UDP));
758 : 0 : udp_hdr->Assign(1, new PortVal(ntohs(up->uh_dport), TRANSPORT_UDP));
759 : 0 : udp_hdr->Assign(2, new Val(ntohs(up->uh_ulen), TYPE_COUNT));
760 : :
761 : 0 : pkt_hdr->Assign(2, udp_hdr);
762 : 0 : break;
763 : : }
764 : :
765 : : case IPPROTO_ICMP:
766 : : {
767 : 0 : const struct icmp* icmpp = (const struct icmp *) data;
768 : 0 : RecordVal* icmp_hdr = new RecordVal(icmp_hdr_type);
769 : :
770 : 0 : icmp_hdr->Assign(0, new Val(icmpp->icmp_type, TYPE_COUNT));
771 : :
772 : 0 : pkt_hdr->Assign(3, icmp_hdr);
773 : : break;
774 : : }
775 : :
776 : : default:
777 : : {
778 : : // This is not a protocol we understand.
779 : : }
780 : : }
781 : :
782 : 0 : return pkt_hdr;
783 : : }
784 : :
785 : : FragReassembler* NetSessions::NextFragment(double t, const IP_Hdr* ip,
786 : 0 : const u_char* pkt, uint32 frag_field)
787 : : {
788 : 0 : uint32 src_addr = uint32(ip->SrcAddr4());
789 : 0 : uint32 dst_addr = uint32(ip->DstAddr4());
790 : 0 : uint32 frag_id = ntohs(ip->ID4()); // we actually could skip conv.
791 : :
792 : 0 : ListVal* key = new ListVal(TYPE_ANY);
793 : 0 : key->Append(new Val(src_addr, TYPE_COUNT));
794 : 0 : key->Append(new Val(dst_addr, TYPE_COUNT));
795 : 0 : key->Append(new Val(frag_id, TYPE_COUNT));
796 : :
797 : 0 : HashKey* h = ch->ComputeHash(key, 1);
798 [ # # ]: 0 : if ( ! h )
799 : 0 : internal_error("hash computation failed");
800 : :
801 : 0 : FragReassembler* f = fragments.Lookup(h);
802 [ # # ]: 0 : if ( ! f )
803 : : {
804 : 0 : f = new FragReassembler(this, ip, pkt, frag_field, h, t);
805 : 0 : fragments.Insert(h, f);
806 : 0 : Unref(key);
807 : 0 : return f;
808 : : }
809 : :
810 [ # # ]: 0 : delete h;
811 : 0 : Unref(key);
812 : :
813 : 0 : f->AddFragment(t, ip, pkt, frag_field);
814 : 0 : return f;
815 : : }
816 : :
817 : : int NetSessions::Get_OS_From_SYN(struct os_type* retval,
818 : : uint16 tot, uint8 DF_flag, uint8 TTL, uint16 WSS,
819 : : uint8 ocnt, uint8* op, uint16 MSS, uint8 win_scale,
820 : : uint32 tstamp, /* uint8 TOS, */ uint32 quirks,
821 : 0 : uint8 ECN) const
822 : : {
823 : : return SYN_OS_Fingerprinter ?
824 : : SYN_OS_Fingerprinter->FindMatch(retval, tot, DF_flag, TTL,
825 : : WSS, ocnt, op, MSS, win_scale, tstamp,
826 [ # # ]: 0 : quirks, ECN) : 0;
827 : : }
828 : :
829 : 0 : bool NetSessions::CompareWithPreviousOSMatch(uint32 addr, int id) const
830 : : {
831 : : return SYN_OS_Fingerprinter ?
832 [ # # ]: 0 : SYN_OS_Fingerprinter->CacheMatch(addr, id) : 0;
833 : : }
834 : :
835 : 8 : Connection* NetSessions::FindConnection(Val* v)
836 : : {
837 : 8 : BroType* vt = v->Type();
838 [ - + # # ]: 8 : if ( ! IsRecord(vt->Tag()) )
[ - + ]
839 : 0 : return 0;
840 : :
841 : 8 : RecordType* vr = vt->AsRecordType();
842 : 8 : const val_list* vl = v->AsRecord();
843 : :
844 : : int orig_h, orig_p; // indices into record's value list
845 : : int resp_h, resp_p;
846 : :
847 [ + - ]: 8 : if ( vr == conn_id )
848 : : {
849 : 8 : orig_h = 0;
850 : 8 : orig_p = 1;
851 : 8 : resp_h = 2;
852 : 8 : resp_p = 3;
853 : : }
854 : :
855 : : else
856 : : {
857 : : // While it's not a conn_id, it may have equivalent fields.
858 : 0 : orig_h = vr->FieldOffset("orig_h");
859 : 0 : resp_h = vr->FieldOffset("resp_h");
860 : 0 : orig_p = vr->FieldOffset("orig_p");
861 : 0 : resp_p = vr->FieldOffset("resp_p");
862 : :
863 [ # # # # ]: 0 : if ( orig_h < 0 || resp_h < 0 || orig_p < 0 || resp_p < 0 )
[ # # ][ # # ]
864 : 0 : return 0;
865 : :
866 : : // ### we ought to check that the fields have the right
867 : : // types, too.
868 : : }
869 : :
870 : 8 : addr_type orig_addr = (*vl)[orig_h]->AsAddr();
871 : 8 : addr_type resp_addr = (*vl)[resp_h]->AsAddr();
872 : :
873 : 8 : PortVal* orig_portv = (*vl)[orig_p]->AsPortVal();
874 : 8 : PortVal* resp_portv = (*vl)[resp_p]->AsPortVal();
875 : :
876 : : ConnID id;
877 : :
878 : : #ifdef BROv6
879 : : id.src_addr = orig_addr;
880 : : id.dst_addr = resp_addr;
881 : : #else
882 : 8 : id.src_addr = &orig_addr;
883 : 8 : id.dst_addr = &resp_addr;
884 : : #endif
885 : :
886 : 8 : id.src_port = htons((unsigned short) orig_portv->Port());
887 : 8 : id.dst_port = htons((unsigned short) resp_portv->Port());
888 : :
889 : 8 : id.is_one_way = 0; // ### incorrect for ICMP connections
890 : :
891 : 8 : HashKey* h = id.BuildConnKey();
892 [ - + ]: 8 : if ( ! h )
893 : 0 : internal_error("hash computation failed");
894 : :
895 : : Dictionary* d;
896 : :
897 [ + - ]: 8 : if ( orig_portv->IsTCP() )
898 : : {
899 [ + - ]: 8 : if ( use_connection_compressor )
900 : : {
901 : 8 : Connection* conn = conn_compressor->Lookup(h);
902 [ + - ]: 8 : delete h;
903 : 8 : return conn;
904 : : }
905 : : else
906 : 0 : d = &tcp_conns;
907 : : }
908 [ # # ]: 0 : else if ( orig_portv->IsUDP() )
909 : 0 : d = &udp_conns;
910 [ # # ]: 0 : else if ( orig_portv->IsICMP() )
911 : 0 : d = &icmp_conns;
912 : : else
913 : : {
914 : : // This can happen due to pseudo-connections we
915 : : // construct, for example for packet headers embedded
916 : : // in ICMPs.
917 [ # # ]: 0 : delete h;
918 : 0 : return 0;
919 : : }
920 : :
921 : 0 : Connection* conn = (Connection*) d->Lookup(h);
922 : :
923 [ # # ]: 0 : delete h;
924 : :
925 : 8 : return conn;
926 : : }
927 : :
928 : 1624 : void NetSessions::Remove(Connection* c)
929 : : {
930 : 1624 : HashKey* k = c->Key();
931 [ + - ]: 1624 : if ( k )
932 : : {
933 : 1624 : c->CancelTimers();
934 : :
935 : 1624 : TCP_Analyzer* ta = (TCP_Analyzer*) c->GetRootAnalyzer();
936 [ + - + + ]: 1624 : if ( ta && c->ConnTransport() == TRANSPORT_TCP )
[ + + ]
937 : : {
938 [ - + ]: 938 : assert(ta->GetTag() == AnalyzerTag::TCP);
939 : 938 : TCP_Endpoint* to = ta->Orig();
940 : 938 : TCP_Endpoint* tr = ta->Resp();
941 : :
942 : 938 : tcp_stats.StateLeft(to->state, tr->state);
943 : : }
944 : :
945 [ - + ]: 1624 : if ( c->IsPersistent() )
946 : 0 : persistence_serializer->Unregister(c);
947 : :
948 : 1624 : c->Done();
949 : :
950 [ + - ]: 1624 : if ( connection_state_remove )
951 : 1624 : c->Event(connection_state_remove, 0);
952 : :
953 : : // Zero out c's copy of the key, so that if c has been Ref()'d
954 : : // up, we know on a future call to Remove() that it's no
955 : : // longer in the dictionary.
956 : 1624 : c->ClearKey();
957 : :
958 [ + + + - : 1624 : switch ( c->ConnTransport() ) {
- ]
959 : : case TRANSPORT_TCP:
960 [ + - ][ + - ]: 938 : if ( use_connection_compressor &&
[ - + ]
961 : : conn_compressor->Remove(k) )
962 : : // Note, if the Remove() returned false
963 : : // then the compressor doesn't know about
964 : : // this connection, which *should* mean that
965 : : // we never gave it the connection in the
966 : : // first place, and thus we should check
967 : : // the regular TCP table instead.
968 : : ;
969 : :
970 [ # # ]: 0 : else if ( ! tcp_conns.RemoveEntry(k) )
971 : 0 : internal_error("connection missing");
972 : 938 : break;
973 : :
974 : : case TRANSPORT_UDP:
975 [ - + ]: 681 : if ( ! udp_conns.RemoveEntry(k) )
976 : 0 : internal_error("connection missing");
977 : 681 : break;
978 : :
979 : : case TRANSPORT_ICMP:
980 [ - + ]: 5 : if ( ! icmp_conns.RemoveEntry(k) )
981 : 0 : internal_error("connection missing");
982 : 5 : break;
983 : :
984 : : case TRANSPORT_UNKNOWN:
985 : 0 : internal_error("unknown transport when removing connection");
986 : : break;
987 : : }
988 : :
989 : 1624 : Unref(c);
990 [ + - ]: 1624 : delete k;
991 : : }
992 : 1624 : }
993 : :
994 : 0 : void NetSessions::Remove(FragReassembler* f)
995 : : {
996 : 0 : HashKey* k = f->Key();
997 [ # # ]: 0 : if ( ! k )
998 : 0 : internal_error("fragment block not in dictionary");
999 : :
1000 [ # # ]: 0 : if ( ! fragments.RemoveEntry(k) )
1001 : 0 : internal_error("fragment block missing");
1002 : :
1003 : 0 : Unref(f);
1004 : 0 : }
1005 : :
1006 : 0 : void NetSessions::Insert(Connection* c)
1007 : : {
1008 [ # # ]: 0 : assert(c->Key());
1009 : :
1010 : 0 : Connection* old = 0;
1011 : :
1012 [ # # # # ]: 0 : switch ( c->ConnTransport() ) {
1013 : : // Remove first. Otherwise the dictioanry would still
1014 : : // reference the old key for already existing connections.
1015 : :
1016 : : case TRANSPORT_TCP:
1017 [ # # ]: 0 : if ( use_connection_compressor )
1018 : 0 : old = conn_compressor->Insert(c);
1019 : : else
1020 : : {
1021 : 0 : old = (Connection*) tcp_conns.Remove(c->Key());
1022 : 0 : tcp_conns.Insert(c->Key(), c);
1023 : : }
1024 : 0 : break;
1025 : :
1026 : : case TRANSPORT_UDP:
1027 : 0 : old = (Connection*) udp_conns.Remove(c->Key());
1028 : 0 : udp_conns.Insert(c->Key(), c);
1029 : 0 : break;
1030 : :
1031 : : case TRANSPORT_ICMP:
1032 : 0 : old = (Connection*) icmp_conns.Remove(c->Key());
1033 : 0 : icmp_conns.Insert(c->Key(), c);
1034 : 0 : break;
1035 : :
1036 : : default:
1037 : 0 : internal_error("unknown connection type");
1038 : : }
1039 : :
1040 [ # # ][ # # ]: 0 : if ( old && old != c )
1041 : : {
1042 : : // Some clean-ups similar to those in Remove() (but invisible
1043 : : // to the script layer).
1044 : 0 : old->CancelTimers();
1045 [ # # ]: 0 : if ( old->IsPersistent() )
1046 : 0 : persistence_serializer->Unregister(old);
1047 [ # # ]: 0 : delete old->Key();
1048 : 0 : old->ClearKey();
1049 : 0 : Unref(old);
1050 : : }
1051 : 0 : }
1052 : :
1053 : 1 : void NetSessions::Drain()
1054 : : {
1055 [ + - ]: 1 : if ( use_connection_compressor )
1056 : 1 : conn_compressor->Drain();
1057 : :
1058 : 1 : IterCookie* cookie = tcp_conns.InitForIteration();
1059 : : Connection* tc;
1060 : :
1061 [ - + ]: 1 : while ( (tc = tcp_conns.NextEntry(cookie)) )
1062 : : {
1063 : 0 : tc->Done();
1064 : 0 : tc->Event(connection_state_remove, 0);
1065 : : }
1066 : :
1067 : 1 : cookie = udp_conns.InitForIteration();
1068 : : Connection* uc;
1069 : :
1070 [ + + ]: 4 : while ( (uc = udp_conns.NextEntry(cookie)) )
1071 : : {
1072 : 3 : uc->Done();
1073 : 3 : uc->Event(connection_state_remove, 0);
1074 : : }
1075 : :
1076 : 1 : cookie = icmp_conns.InitForIteration();
1077 : : Connection* ic;
1078 : :
1079 [ - + ]: 1 : while ( (ic = icmp_conns.NextEntry(cookie)) )
1080 : : {
1081 : 0 : ic->Done();
1082 : 0 : ic->Event(connection_state_remove, 0);
1083 : : }
1084 : :
1085 : 1 : ExpireTimerMgrs();
1086 : 1 : }
1087 : :
1088 : 0 : void NetSessions::HeartBeat(double t)
1089 : : {
1090 : 0 : unsigned int recv = 0;
1091 : 0 : unsigned int drop = 0;
1092 : 0 : unsigned int link = 0;
1093 : :
1094 [ # # ]: 0 : loop_over_list(pkt_srcs, i)
1095 : : {
1096 : 0 : PktSrc* ps = pkt_srcs[i];
1097 : :
1098 : : struct PktSrc::Stats stat;
1099 : 0 : ps->Statistics(&stat);
1100 : 0 : recv += stat.received;
1101 : 0 : drop += stat.dropped;
1102 : 0 : link += stat.link;
1103 : : }
1104 : :
1105 : 0 : val_list* vl = new val_list;
1106 : :
1107 : 0 : vl->append(new Val(t, TYPE_TIME));
1108 : :
1109 : 0 : RecordVal* ns = new RecordVal(net_stats);
1110 : 0 : ns->Assign(0, new Val(recv, TYPE_COUNT));
1111 : 0 : ns->Assign(1, new Val(drop, TYPE_COUNT));
1112 : 0 : ns->Assign(2, new Val(link, TYPE_COUNT));
1113 : :
1114 : 0 : vl->append(ns);
1115 : :
1116 : 0 : mgr.QueueEvent(net_stats_update, vl);
1117 : :
1118 : 0 : timer_mgr->Add(new NetworkTimer(this, t + heartbeat_interval));
1119 : 0 : }
1120 : :
1121 : 0 : void NetSessions::GetStats(SessionStats& s) const
1122 : : {
1123 : 0 : s.num_TCP_conns = tcp_conns.Length();
1124 : 0 : s.num_UDP_conns = udp_conns.Length();
1125 : 0 : s.num_ICMP_conns = icmp_conns.Length();
1126 : 0 : s.num_fragments = fragments.Length();
1127 : 0 : s.num_packets = num_packets_processed;
1128 : 0 : s.num_timers = timer_mgr->Size();
1129 : 0 : s.num_events_queued = num_events_queued;
1130 : 0 : s.num_events_dispatched = num_events_dispatched;
1131 : :
1132 : 0 : s.max_TCP_conns = tcp_conns.MaxLength();
1133 : 0 : s.max_UDP_conns = udp_conns.MaxLength();
1134 : 0 : s.max_ICMP_conns = icmp_conns.MaxLength();
1135 : 0 : s.max_fragments = fragments.MaxLength();
1136 : 0 : s.max_timers = timer_mgr->PeakSize();
1137 : 0 : }
1138 : :
1139 : : Connection* NetSessions::NewConn(HashKey* k, double t, const ConnID* id,
1140 : 1627 : const u_char* data, int proto)
1141 : : {
1142 : : // FIXME: This should be cleaned up a bit, it's too protocol-specific.
1143 : : // But I'm not yet sure what the right abstraction for these things is.
1144 : 1627 : int src_h = ntohs(id->src_port);
1145 : 1627 : int dst_h = ntohs(id->dst_port);
1146 : 1627 : int flags = 0;
1147 : :
1148 : : // Hmm... This is not great.
1149 : : TransportProto tproto;
1150 [ + + + - ]: 1627 : switch ( proto ) {
1151 : : case IPPROTO_ICMP:
1152 : 5 : tproto = TRANSPORT_ICMP;
1153 : 5 : break;
1154 : : case IPPROTO_TCP:
1155 : 938 : tproto = TRANSPORT_TCP;
1156 : 938 : break;
1157 : : case IPPROTO_UDP:
1158 : 684 : tproto = TRANSPORT_UDP;
1159 : 684 : break;
1160 : : default:
1161 : 0 : internal_error("unknown transport protocol");
1162 : : break;
1163 : : };
1164 : :
1165 [ + + ]: 1627 : if ( tproto == TRANSPORT_TCP )
1166 : : {
1167 : 938 : const struct tcphdr* tp = (const struct tcphdr*) data;
1168 : 938 : flags = tp->th_flags;
1169 : : }
1170 : :
1171 : 1627 : bool flip = false;
1172 : :
1173 [ - + ]: 1627 : if ( ! WantConnection(src_h, dst_h, tproto, flags, flip) )
1174 : 0 : return 0;
1175 : :
1176 [ + + ]: 1627 : if ( flip )
1177 : : {
1178 : : // Make a guess that we're seeing the tail half of
1179 : : // an analyzable connection.
1180 : 387 : ConnID flip_id = *id;
1181 : :
1182 : 387 : const uint32* ta = flip_id.src_addr;
1183 : 387 : flip_id.src_addr = flip_id.dst_addr;
1184 : 387 : flip_id.dst_addr = ta;
1185 : :
1186 : 387 : uint32 t = flip_id.src_port;
1187 : 387 : flip_id.src_port = flip_id.dst_port;
1188 : 387 : flip_id.dst_port = t;
1189 : :
1190 : 387 : id = &flip_id;
1191 : : }
1192 : :
1193 : 1627 : Connection* conn = new Connection(this, k, t, id);
1194 : 1627 : conn->SetTransport(tproto);
1195 : 1627 : dpm->BuildInitialAnalyzerTree(tproto, conn, data);
1196 : :
1197 : 1627 : bool external = conn->IsExternal();
1198 : :
1199 [ - + ]: 1627 : if ( external )
1200 : : conn->AppendAddl(fmt("tag=%s",
1201 : 0 : conn->GetTimerMgr()->GetTag().c_str()));
1202 : :
1203 : : // If the connection compressor is active, it takes care of the
1204 : : // new_connection/connection_external events for TCP connections.
1205 [ + - ][ + + ]: 1627 : if ( new_connection &&
[ - + ][ + + ]
1206 : : (tproto != TRANSPORT_TCP || ! use_connection_compressor) )
1207 : : {
1208 : 689 : conn->Event(new_connection, 0);
1209 : :
1210 [ - + ]: 689 : if ( external )
1211 : : {
1212 : 0 : val_list* vl = new val_list(2);
1213 : 0 : vl->append(conn->BuildConnVal());
1214 : 0 : vl->append(new StringVal(conn->GetTimerMgr()->GetTag().c_str()));
1215 : 0 : conn->ConnectionEvent(connection_external, 0, vl);
1216 : : }
1217 : : }
1218 : :
1219 : 1627 : return conn;
1220 : : }
1221 : :
1222 : 1880 : bool NetSessions::IsLikelyServerPort(uint32 port, TransportProto proto) const
1223 : : {
1224 : : // We keep a cached in-core version of the table to speed up the lookup.
1225 [ + + ][ + - ]: 1881 : static set<bro_uint_t> port_cache;
[ # # ]
1226 : : static bool have_cache = false;
1227 : :
1228 [ + + ]: 1880 : if ( ! have_cache )
1229 : : {
1230 : 1 : ListVal* lv = likely_server_ports->ConvertToPureList();
1231 [ + + ]: 55 : for ( int i = 0; i < lv->Length(); i++ )
1232 : 54 : port_cache.insert(lv->Index(i)->InternalUnsigned());
1233 : 1 : have_cache = true;
1234 : 1 : Unref(lv);
1235 : : }
1236 : :
1237 : : // We exploit our knowledge of PortVal's internal storage mechanism
1238 : : // here.
1239 [ + + ]: 1880 : if ( proto == TRANSPORT_TCP )
1240 : 1063 : port |= TCP_PORT_MASK;
1241 [ + - ]: 817 : else if ( proto == TRANSPORT_UDP )
1242 : 817 : port |= UDP_PORT_MASK;
1243 [ # # ]: 0 : else if ( proto == TRANSPORT_ICMP )
1244 : 0 : port |= ICMP_PORT_MASK;
1245 : :
1246 : 1880 : return port_cache.find(port) != port_cache.end();
1247 : : }
1248 : :
1249 : : bool NetSessions::WantConnection(uint16 src_port, uint16 dst_port,
1250 : : TransportProto transport_proto,
1251 : 2317 : uint8 tcp_flags, bool& flip_roles)
1252 : : {
1253 : 2317 : flip_roles = false;
1254 : :
1255 [ + + ]: 2317 : if ( transport_proto == TRANSPORT_TCP )
1256 : : {
1257 [ + + ][ + + ]: 1628 : if ( ! (tcp_flags & TH_SYN) || (tcp_flags & TH_ACK) )
1258 : : {
1259 : : // The new connection is starting either without a SYN,
1260 : : // or with a SYN ack. This means it's a partial connection.
1261 [ - + ]: 632 : if ( ! partial_connection_ok )
1262 : 0 : return false;
1263 : :
1264 [ + + ][ - + ]: 632 : if ( tcp_flags & TH_SYN && ! tcp_SYN_ack_ok )
1265 : 0 : return false;
1266 : :
1267 : : // Try to guess true responder by the port numbers.
1268 : : // (We might also think that for SYN acks we could
1269 : : // safely flip the roles, but that doesn't work
1270 : : // for stealth scans.)
1271 [ + + ]: 632 : if ( IsLikelyServerPort(src_port, TRANSPORT_TCP) )
1272 : : { // connection is a candidate for flipping
1273 [ - + ]: 431 : if ( IsLikelyServerPort(dst_port, TRANSPORT_TCP) )
1274 : : // Hmmm, both source and destination
1275 : : // are plausible. Heuristic: flip only
1276 : : // if (1) this isn't a SYN ACK (to avoid
1277 : : // confusing stealth scans) and
1278 : : // (2) dest port > src port (to favor
1279 : : // more plausible servers).
1280 [ # # ][ # # ]: 0 : flip_roles = ! (tcp_flags & TH_SYN) && src_port < dst_port;
1281 : : else
1282 : : // Source is plausible, destination isn't.
1283 : 1628 : flip_roles = true;
1284 : : }
1285 : : }
1286 : : }
1287 : :
1288 [ + + ]: 689 : else if ( transport_proto == TRANSPORT_UDP )
1289 : : flip_roles =
1290 : : IsLikelyServerPort(src_port, TRANSPORT_UDP) &&
1291 [ + + ][ + + ]: 684 : ! IsLikelyServerPort(dst_port, TRANSPORT_UDP);
1292 : :
1293 : 2317 : return true;
1294 : : }
1295 : :
1296 : 42694 : TimerMgr* NetSessions::LookupTimerMgr(const TimerMgr::Tag* tag, bool create)
1297 : : {
1298 [ + - ]: 42694 : if ( ! tag )
1299 : : {
1300 : 42694 : DBG_LOG(DBG_TM, "no tag, using global timer mgr %p", timer_mgr);
1301 : 42694 : return timer_mgr;
1302 : : }
1303 : :
1304 : 0 : TimerMgrMap::iterator i = timer_mgrs.find(*tag);
1305 [ # # ]: 0 : if ( i != timer_mgrs.end() )
1306 : : {
1307 : 0 : DBG_LOG(DBG_TM, "tag %s, using non-global timer mgr %p", tag->c_str(), i->second);
1308 : 0 : return i->second;
1309 : : }
1310 : : else
1311 : : {
1312 [ # # ]: 0 : if ( ! create )
1313 : 0 : return 0;
1314 : :
1315 : : // Create new queue for tag.
1316 : 0 : TimerMgr* mgr = new CQ_TimerMgr(*tag);
1317 : 0 : DBG_LOG(DBG_TM, "tag %s, creating new non-global timer mgr %p", tag->c_str(), mgr);
1318 : 42694 : timer_mgrs.insert(TimerMgrMap::value_type(*tag, mgr));
1319 : 0 : double t = timer_mgr->Time() + timer_mgr_inactivity_timeout;
1320 : 0 : timer_mgr->Add(new TimerMgrExpireTimer(t, mgr));
1321 : 0 : return mgr;
1322 : : }
1323 : : }
1324 : :
1325 : 1 : void NetSessions::ExpireTimerMgrs()
1326 : : {
1327 [ - + ]: 1 : for ( TimerMgrMap::iterator i = timer_mgrs.begin();
1328 : : i != timer_mgrs.end(); ++i )
1329 : : {
1330 : 0 : i->second->Expire();
1331 [ # # ]: 0 : delete i->second;
1332 : : }
1333 : 1 : }
1334 : :
1335 : : void NetSessions::DumpPacket(const struct pcap_pkthdr* hdr,
1336 : 20378 : const u_char* pkt, int len)
1337 : : {
1338 [ + - ]: 20378 : if ( ! pkt_dumper )
1339 : 20378 : return;
1340 : :
1341 [ # # ]: 0 : if ( len == 0 )
1342 : 0 : pkt_dumper->Dump(hdr, pkt);
1343 : : else
1344 : : {
1345 : 0 : struct pcap_pkthdr h = *hdr;
1346 : 0 : h.caplen = len;
1347 [ # # ]: 0 : if ( h.caplen > hdr->caplen )
1348 : 0 : internal_error("bad modified caplen");
1349 : 20378 : pkt_dumper->Dump(&h, pkt);
1350 : : }
1351 : : }
1352 : :
1353 : : void NetSessions::Internal(const char* msg, const struct pcap_pkthdr* hdr,
1354 : 0 : const u_char* pkt)
1355 : : {
1356 : 0 : DumpPacket(hdr, pkt);
1357 : 0 : internal_error(msg);
1358 : : }
1359 : :
1360 : : void NetSessions::Weird(const char* name,
1361 : 969 : const struct pcap_pkthdr* hdr, const u_char* pkt)
1362 : : {
1363 [ + - ]: 969 : if ( hdr )
1364 : 969 : dump_this_packet = 1;
1365 : :
1366 [ + - ]: 969 : if ( net_weird )
1367 : : {
1368 : 969 : val_list* vl = new val_list;
1369 : 969 : vl->append(new StringVal(name));
1370 : 969 : mgr.QueueEvent(net_weird, vl);
1371 : : }
1372 : : else
1373 : 0 : fprintf(stderr, "weird: %.06f %s\n", network_time, name);
1374 : 969 : }
1375 : :
1376 : 0 : void NetSessions::Weird(const char* name, const IP_Hdr* ip)
1377 : : {
1378 [ # # ]: 0 : if ( flow_weird )
1379 : : {
1380 : 0 : val_list* vl = new val_list;
1381 : 0 : vl->append(new StringVal(name));
1382 : 0 : vl->append(new AddrVal(ip->SrcAddr4()));
1383 : 0 : vl->append(new AddrVal(ip->DstAddr4()));
1384 : 0 : mgr.QueueEvent(flow_weird, vl);
1385 : : }
1386 : : else
1387 : 0 : fprintf(stderr, "weird: %.06f %s\n", network_time, name);
1388 : 0 : }
1389 : :
1390 : 0 : unsigned int NetSessions::ConnectionMemoryUsage()
1391 : : {
1392 : 0 : unsigned int mem = 0;
1393 : :
1394 [ # # ]: 0 : if ( terminating )
1395 : : // Connections have been flushed already.
1396 : 0 : return 0;
1397 : :
1398 : 0 : IterCookie* cookie = tcp_conns.InitForIteration();
1399 : : Connection* tc;
1400 : :
1401 [ # # ]: 0 : while ( (tc = tcp_conns.NextEntry(cookie)) )
1402 : 0 : mem += tc->MemoryAllocation();
1403 : :
1404 : 0 : cookie = udp_conns.InitForIteration();
1405 : : Connection* uc;
1406 : :
1407 [ # # ]: 0 : while ( (uc = udp_conns.NextEntry(cookie)) )
1408 : 0 : mem += uc->MemoryAllocation();
1409 : :
1410 : 0 : cookie = icmp_conns.InitForIteration();
1411 : : Connection* ic;
1412 : :
1413 [ # # ]: 0 : while ( (ic = icmp_conns.NextEntry(cookie)) )
1414 : 0 : mem += ic->MemoryAllocation();
1415 : :
1416 : 0 : return mem;
1417 : : }
1418 : :
1419 : 0 : unsigned int NetSessions::ConnectionMemoryUsageConnVals()
1420 : : {
1421 : 0 : unsigned int mem = 0;
1422 : :
1423 [ # # ]: 0 : if ( terminating )
1424 : : // Connections have been flushed already.
1425 : 0 : return 0;
1426 : :
1427 : 0 : IterCookie* cookie = tcp_conns.InitForIteration();
1428 : : Connection* tc;
1429 : :
1430 [ # # ]: 0 : while ( (tc = tcp_conns.NextEntry(cookie)) )
1431 : 0 : mem += tc->MemoryAllocationConnVal();
1432 : :
1433 : 0 : cookie = udp_conns.InitForIteration();
1434 : : Connection* uc;
1435 : :
1436 [ # # ]: 0 : while ( (uc = udp_conns.NextEntry(cookie)) )
1437 : 0 : mem += uc->MemoryAllocationConnVal();
1438 : :
1439 : 0 : cookie = icmp_conns.InitForIteration();
1440 : : Connection* ic;
1441 : :
1442 [ # # ]: 0 : while ( (ic = icmp_conns.NextEntry(cookie)) )
1443 : 0 : mem += ic->MemoryAllocationConnVal();
1444 : :
1445 : 0 : return mem;
1446 : : }
1447 : :
1448 : 0 : unsigned int NetSessions::MemoryAllocation()
1449 : : {
1450 [ # # ]: 0 : if ( terminating )
1451 : : // Connections have been flushed already.
1452 : 0 : return 0;
1453 : :
1454 : : return ConnectionMemoryUsage()
1455 : : + padded_sizeof(*this)
1456 : : + ch->MemoryAllocation()
1457 : : // must take care we don't count the HaskKeys twice.
1458 : : + tcp_conns.MemoryAllocation() - padded_sizeof(tcp_conns) -
1459 : : // 12 is sizeof(Key) from ConnID::BuildConnKey();
1460 : : // it can't be (easily) accessed here. :-(
1461 : : (tcp_conns.Length() * pad_size(12))
1462 : : + udp_conns.MemoryAllocation() - padded_sizeof(udp_conns) -
1463 : : (udp_conns.Length() * pad_size(12))
1464 : : + icmp_conns.MemoryAllocation() - padded_sizeof(icmp_conns) -
1465 : : (icmp_conns.Length() * pad_size(12))
1466 : 0 : + fragments.MemoryAllocation() - padded_sizeof(fragments)
1467 : : // FIXME: MemoryAllocation() not implemented for rest.
1468 : : ;
1469 [ + - ][ + - ]: 6 : }
|