1 /**
2 *
3 * tcpdemux.cpp
4 * A tcpip demultiplier.
5 *
6 * This file is part of tcpflow by Simson Garfinkel,
7 * originally by Jeremy Elson <jelson@circlemud.org>
8 *
9 * This source code is under the GNU Public License (GPL). See
10 * LICENSE for details.
11 *
12 */
13
14 #include "tcpflow.h"
15 #include "tcpip.h"
16 #include "tcpdemux.h"
17
18 #include <iostream>
19 #include <sstream>
20 #include <vector>
21
22 /* static */ uint32_t tcpdemux::max_saved_flows = 100;
23 /* static */ uint32_t tcpdemux::tcp_timeout = 0;
24
tcpdemux()25 tcpdemux::tcpdemux():
26 #ifdef HAVE_SQLITE3
27 db(),insert_flow(),
28 #endif
29 outdir("."),flow_counter(0),packet_counter(0),
30 xreport(0),pwriter(0),max_open_flows(),max_fds(get_max_fds()-NUM_RESERVED_FDS),
31 flow_map(),open_flows(),saved_flow_map(),
32 saved_flows(),start_new_connections(false),opt(),fs()
33 {
34 }
35
openDB()36 void tcpdemux::openDB()
37 {
38 #ifdef HAVE_SQLITE3
39 int rc = sqlite3_open("test.db", &db);
40 if( rc ){
41 fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
42 db = 0;
43 }
44 /* Create SQL statement */
45 const char *sql = "CREATE TABLE connections ("
46 "starttime TEXT NOT NULL,"
47 "endtime TEXT NOT NULL,"
48 "src_ipn TEXT,"
49 "dst_ipn TEXT,"
50 "mac_daddr TEXT,"
51 "mac_saddr TEXT,"
52 "packets INTEGER,"
53 "srcport INTEGER,"
54 "dstport INTEGER,"
55 "hashdigest_md5 TEXT);";
56
57 /* Execute SQL statement */
58 rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
59 if( rc != SQLITE_OK ){
60 fprintf(stderr, "SQL error: %s\n", zErrMsg);
61 sqlite3_free(zErrMsg);
62 sqlite3_close(db);
63 return 0;
64 }
65 const char* zSql = "INSERT INTO connections (starttime,endtime,src_ipn,dst_ipn,mac_daddr,mac_saddr,packets,srcport,dstport,hashdigest_md5) VALUES (?,?,?,?,?,?,?,?,?,?)";
66 if(sqlite3_prepare_v2(db, zSql, strlen(zSql), &insert_stmt, NULL)!=SQLITE_OK ){
67 fprintf(stderr, "SQL prepare error");
68 db = 0;
69 insert_stmt=0;
70 return(0);
71 }
72 #endif
73 }
74
write_flow_record(const std::string & starttime,const std::string & endtime,const std::string & src_ipn,const std::string & dst_ipn,const std::string & mac_daddr,const std::string & mac_saddr,uint64_t packets,uint16_t srcport,uint16_t dstport,const std::string & hashdigest_md5)75 void tcpdemux::write_flow_record(const std::string &starttime,const std::string &endtime,
76 const std::string &src_ipn,const std::string &dst_ipn,
77 const std::string &mac_daddr,const std::string &mac_saddr,
78 uint64_t packets,uint16_t srcport,uint16_t dstport,
79 const std::string &hashdigest_md5)
80 {
81 }
82
83
84
getInstance()85 /* static */ tcpdemux *tcpdemux::getInstance()
86 {
87 static tcpdemux * theInstance = 0;
88 if(theInstance==0) theInstance = new tcpdemux();
89 return theInstance;
90 }
91
92 /**
93 * find the flow that has been written to in the furthest past and close it.
94 */
close_oldest_fd()95 void tcpdemux::close_oldest_fd()
96 {
97 tcpip *oldest_tcp = *open_flows.begin();
98 if(oldest_tcp) oldest_tcp->close_file();
99 }
100
101 /* Open a file, closing one of the existing flows f necessary.
102 */
retrying_open(const std::string & filename,int oflag,int mask)103 int tcpdemux::retrying_open(const std::string &filename,int oflag,int mask)
104 {
105 while(true){
106 //Packet index file reduces max_fds by 1/2 as the index files also take a fd
107 if(open_flows.size() >= (opt.output_packet_index ? max_fds/2 : max_fds)) close_oldest_fd();
108 int fd = ::open(filename.c_str(),oflag,mask);
109 DEBUG(2)("retrying_open ::open(fn=%s,oflag=x%x,mask:x%x)=%d",filename.c_str(),oflag,mask,fd);
110 if(fd>=0){
111 /* Open was successful */
112 return fd;
113 }
114 DEBUG(2)("retrying_open ::open failed with errno=%d",errno);
115 if (errno != ENFILE && errno != EMFILE){
116 DEBUG(2)("retrying_open ::open failed with errno=%d (%s)",errno,strerror(errno));
117 return -1; // wonder what it was
118 }
119 DEBUG(5) ("too many open files -- contracting FD ring (size=%d)", (int)open_flows.size());
120 close_oldest_fd();
121 }
122 }
123
124 /* Find previously a previously created flow state in the database.
125 */
find_tcpip(const flow_addr & flow)126 tcpip *tcpdemux::find_tcpip(const flow_addr &flow)
127 {
128 flow_map_t::const_iterator it = flow_map.find(flow);
129 if (it==flow_map.end()){
130 return NULL; // flow not found
131 }
132 return it->second;
133 }
134
135 /* Create a new flow state structure for a given flow.
136 * Puts the flow in the map.
137 * Returns a pointer to the new state.
138 *
139 * This is called by tcpdemux::process_tcp(). (Only place it is called)
140 *
141 * @param - pi - first packet seen on this connection.
142 *
143 * NOTE: We keep pointers to tcp structures in the map, rather than
144 * the structures themselves. This makes the map slightly more efficient,
145 * since it doesn't need to shuffle entire structures.
146 *
147 *
148 * TK: Note that the flow() is created on the stack and then used in new tcpip().
149 * This is resulting in an unnecessary copy.
150 */
151
create_tcpip(const flow_addr & flowa,be13::tcp_seq isn,const be13::packet_info & pi)152 tcpip *tcpdemux::create_tcpip(const flow_addr &flowa, be13::tcp_seq isn,const be13::packet_info &pi)
153 {
154 /* create space for the new state */
155 flow flow(flowa,flow_counter++,pi);
156
157 tcpip *new_tcpip = new tcpip(*this,flow,isn);
158 new_tcpip->nsn = isn+1; // expected sequence number of the first byte
159 DEBUG(5) ("new flow %s. path: %s next seq num (nsn):%d",
160 flowa.str().c_str(),new_tcpip->flow_pathname.c_str(),new_tcpip->nsn);
161 flow_map[flow] = new_tcpip;
162 open_flows.reset(new_tcpip);
163 return new_tcpip;
164 }
165
166 /**
167 * Remove a flow from the database.
168 * Close the flow file.
169 * Write to the report.xml object.
170 * Save in the sqlite database.
171 * This is the ONLY place where a tcpip object is deleted so there is no chance of finding it again.
172 *
173 * Flows are post-processed when a FIN is received and all bytes are received.
174 * If a FIN is received and bytes are outstanding, they are post-processed when the last byte is received.
175 * When the program shut down, all open flows are post-processed.
176 *
177 * Amended to trigger the packet/data location index sort as part of the post-processing. This sorts
178 * the (potentially out of order) index to make it simple for external applications. No processing is
179 * done if the (-I) index generation feature is turned off. --GDD
180 */
181
post_process(tcpip * tcp)182 void tcpdemux::post_process(tcpip *tcp)
183 {
184 std::stringstream xmladd; // for this <fileobject>
185 if(opt.post_processing && tcp->file_created && tcp->last_byte>0){
186 /**
187 * After the flow is finished, if more than a byte was
188 * written, then put it in an SBUF and process it. if we are
189 * doing post-processing. This is called from tcpip::~tcpip()
190 * in tcpip.cpp.
191 */
192
193 /* Open the fd if it is not already open */
194 tcp->open_file();
195 if(tcp->fd>=0){
196 sbuf_t *sbuf = sbuf_t::map_file(tcp->flow_pathname,tcp->fd);
197 if(sbuf){
198 be13::plugin::process_sbuf(scanner_params(scanner_params::PHASE_SCAN,*sbuf,*(fs),&xmladd));
199 delete sbuf;
200 sbuf = 0;
201 }
202 }
203 }
204 tcp->close_file();
205 if(xreport) tcp->dump_xml(xreport,xmladd.str());
206 /**
207 * Before we delete the tcp structure, save information about the saved flow
208 */
209 save_flow(tcp);
210 delete tcp;
211 }
212
remove_flow(const flow_addr & flow)213 void tcpdemux::remove_flow(const flow_addr &flow)
214 {
215 flow_map_t::iterator it = flow_map.find(flow);
216 if(it!=flow_map.end()){
217 post_process(it->second);
218 flow_map.erase(it);
219 }
220 }
221
remove_all_flows()222 void tcpdemux::remove_all_flows()
223 {
224 for(flow_map_t::iterator it=flow_map.begin();it!=flow_map.end();it++){
225 post_process(it->second);
226 }
227 flow_map.clear();
228 }
229
230 /****************************************************************
231 *** tcpdemultiplexer
232 ****************************************************************/
233
234 /* Try to find the maximum number of FDs this system can have open */
get_max_fds(void)235 unsigned int tcpdemux::get_max_fds(void)
236 {
237 int max_descs = 0;
238 const char *method=0;
239
240 /* No longer users OPEN_MAX */
241 #if defined (HAVE_GETDTABLESIZE)
242 method = "getdtablesize";
243 max_descs = getdtablesize();
244 #elif defined(RLIMIT_NOFILE)
245 {
246 struct rlimit limit;
247 memset(&limit,0,sizeof(limit));
248
249 method = "rlimit";
250 if (getrlimit(RLIMIT_NOFILE, &limit) < 0) {
251 perror("getrlimit");
252 exit(1);
253 }
254
255 /* set the current to the maximum or specified value */
256 limit.rlim_cur = limit.rlim_max;
257 #ifdef OPEN_MAX
258 if(limit.rlim_cur > OPEN_MAX) limit.rlim_cur = OPEN_MAX;
259 #endif
260
261 if (setrlimit(RLIMIT_NOFILE, &limit) < 0) {
262 perror("setrlimit");
263 exit(1);
264 }
265 max_descs = limit.rlim_max;
266
267 #ifdef RLIM_INFINITY
268 if (limit.rlim_max == RLIM_INFINITY) max_descs = MAX_FD_GUESS * 4; /* pick a more reasonable max */
269 #endif
270 }
271 #elif defined (_SC_OPEN_MAX)
272 /* Okay, you don't have getrlimit() and you don't have OPEN_MAX.
273 * Time to try the POSIX sysconf() function. (See Stevens'
274 * _Advanced Programming in the UNIX Environment_). */
275 method = "POSIX sysconf";
276 errno = 0;
277 if ((max_descs = sysconf(_SC_OPEN_MAX)) < 0) {
278 if (errno == 0)
279 max_descs = MAX_FD_GUESS * 4;
280 else {
281 perror("calling sysconf");
282 exit(1);
283 }
284 }
285
286 /* if everything has failed, we'll just take a guess */
287 #else
288 method = "MAX_FD_GUESS";
289 max_descs = MAX_FD_GUESS;
290 #endif
291 /* this must go here, after rlimit code */
292 DEBUG(10) ("found max FDs to be %d using %s", max_descs, method);
293 return max_descs;
294 }
295
296
297 /*
298 * open the packet save flow
299 */
save_unk_packets(const std::string & ofname,const std::string & ifname)300 void tcpdemux::save_unk_packets(const std::string &ofname,const std::string &ifname)
301 {
302 pwriter = pcap_writer::open_copy(ofname,ifname);
303 }
304
305 /**
306 * save information on this flow needed to handle strangling packets
307 */
308 int c = 0;
save_flow(tcpip * tcp)309 void tcpdemux::save_flow(tcpip *tcp)
310 {
311 /* First remove the oldest flow if we are in overload */
312 if(saved_flows.size()>0 && saved_flows.size()>max_saved_flows){
313 saved_flow *flow0 = saved_flows.at(0);
314 saved_flow_map.erase(flow0->addr); // remove from the map
315 saved_flows.erase(saved_flows.begin()); // remove from the vector
316 delete flow0; // and delete the saved flow
317 }
318
319 /* Now save the flow */
320 saved_flow *sf = new saved_flow(tcp);
321 saved_flow_map[sf->addr] = sf;
322 saved_flows.push_back(sf);
323 }
324
325
326 /**
327 * process_tcp():
328 *
329 * Called to processes a tcp packet from either process_ip4() or process_ip6().
330 * The caller breaks out the ip addresses and finds the start of the tcp header.
331 *
332 * Skips but otherwise ignores TCP options.
333 *
334 * creates a new tcp connection if necessary, then asks the connection to either
335 * print the packet or store it.
336 *
337 * Returns 0 if packet is processed, 1 if it is not processed, -1 if error
338 */
339
340 #define FLAG_SET(vector, flag) ((vector) & (flag))
341
342 #pragma GCC diagnostic ignored "-Wcast-align"
343 #include "iptree.h"
344
process_tcp(const ipaddr & src,const ipaddr & dst,sa_family_t family,const u_char * ip_data,uint32_t ip_payload_len,const be13::packet_info & pi)345 int tcpdemux::process_tcp(const ipaddr &src, const ipaddr &dst,sa_family_t family,
346 const u_char *ip_data, uint32_t ip_payload_len,
347 const be13::packet_info &pi)
348 {
349 if (ip_payload_len < sizeof(struct be13::tcphdr)) {
350 DEBUG(6) ("received truncated TCP segment! (%u<%u)",
351 (u_int)ip_payload_len,(u_int)sizeof(struct be13::tcphdr));
352 return 1;
353 }
354
355 struct be13::tcphdr *tcp_header = (struct be13::tcphdr *) ip_data;
356
357 /* fill in the flow_addr structure with info that identifies this flow */
358 flow_addr this_flow(src,dst,ntohs(tcp_header->th_sport),ntohs(tcp_header->th_dport),family);
359
360 be13::tcp_seq seq = ntohl(tcp_header->th_seq);
361 bool syn_set = FLAG_SET(tcp_header->th_flags, TH_SYN);
362 bool ack_set = FLAG_SET(tcp_header->th_flags, TH_ACK);
363 bool fin_set = FLAG_SET(tcp_header->th_flags, TH_FIN);
364 bool rst_set = FLAG_SET(tcp_header->th_flags, TH_RST);
365
366 /* calculate the total length of the TCP header including options */
367 u_int tcp_header_len = tcp_header->th_off * 4;
368
369 /* Find the beginning of the tcp data.
370 */
371 const u_char *tcp_data = ip_data + tcp_header_len;
372
373 /* figure out how much tcp data we have, taking into account tcp options */
374
375 size_t tcp_datalen = (ip_payload_len > tcp_header_len) ? (ip_payload_len - tcp_header_len) : 0;
376
377 /* see if we have state about this flow; if not, create it */
378 int32_t delta = 0; // from current position in tcp connection; must be SIGNED 32 bit!
379 tcpip *tcp = find_tcpip(this_flow);
380
381 DEBUG(60)("%s%s%s%s tcp_header_len=%d tcp_datalen=%d seq=%u tcp=%p",
382 (syn_set?"SYN ":""),(ack_set?"ACK ":""),(fin_set?"FIN ":""),(rst_set?"RST ":""),(int)tcp_header_len,(int)tcp_datalen,(int)seq,tcp);
383
384 /* If this_flow is not in the database and the start_new_connections flag is false, just return */
385 if(tcp==0 && start_new_connections==false) return 0;
386
387 if(syn_set && tcp && tcp->syn_count>0 && tcp->pos>0){
388 std::cerr << "SYN TO IGNORE! SYN tcp="<<tcp << " flow="<<this_flow<<"\n";
389 return 1;
390 }
391
392 if(tcp==0){
393 if(tcp_datalen==0){ // zero length packet
394 if(fin_set) return 0; // FIN on a connection that's unknown; safe to ignore
395 if(rst_set) return 0; // RST on a connection that's unknown; safe to ignore
396 if(syn_set==false && ack_set==false) return 0; // neither a SYN nor ACK; return
397 } else {
398 /* Data present on a flow that is not actively being demultiplexed.
399 * See if it is a saved flow. If so, see if the data in the packet
400 * matches what is on the disk. If so, return.
401 *
402 */
403 saved_flow_map_t::const_iterator it = saved_flow_map.find(this_flow);
404 if(it!=saved_flow_map.end()){
405 uint32_t offset = seq - it->second->isn - 1;
406 bool data_match = false;
407 int fd = open(it->second->saved_filename.c_str(),O_RDONLY | O_BINARY);
408 if(fd>0){
409 char *buf = (char *)malloc(tcp_datalen);
410 if(buf){
411 DEBUG(100)("lseek(fd,%" PRId64 ",SEEK_SET)",(int64_t)(offset));
412 lseek(fd,offset,SEEK_SET);
413 ssize_t r = read(fd,buf,tcp_datalen);
414 data_match = (r==(ssize_t)tcp_datalen) && memcmp(buf,tcp_data,tcp_datalen)==0;
415 free(buf);
416 }
417 close(fd);
418 }
419 DEBUG(60)("Packet matches saved flow. offset=%u len=%d filename=%s data match=%d\n",
420 (u_int)offset,(u_int)tcp_datalen,it->second->saved_filename.c_str(),(u_int)data_match);
421 if(data_match) return 0;
422 }
423 }
424 }
425
426 /* flow is in the database; make sure the gap isn't too big.*/
427 if(tcp){
428 /* Compute delta based on next expected sequence number.
429 * If delta will be too much, start a new flow.
430 *
431 * NOTE: I hope we don't get a packet from the old flow when
432 * we are processing the new one. Perhaps we should be able to have
433 * multiple flows at the same time with the same quad, and they are
434 * at different window areas...
435 *
436 */
437 delta = seq - tcp->nsn; // notice that signed offset is calculated
438
439 if(abs(delta) > opt.max_seek){
440 remove_flow(this_flow);
441 delta = 0;
442 tcp = 0;
443 }
444 }
445
446 /* At this point, tcp may be NULL because:
447 * case 1 - It's a new connection and SYN IS SET; normal case
448 * case 2 - Extra packets on a now-closed connection
449 * case 3 - Packets for which the initial part of the connection was missed
450 * case 4 - It's a connecton that had a huge gap and was expired out of the databsae
451 *
452 * THIS IS THE ONLY PLACE THAT create_tcpip() is called.
453 */
454
455 /* q: what if syn is set AND there is data? */
456 /* q: what if syn is set AND we already know about this connection? */
457
458 if (tcp==NULL){
459
460 /* Don't process if this is not a SYN and there is no data. */
461 if(syn_set==false && tcp_datalen==0) return 0;
462
463 /* Create a new connection.
464 * delta will be 0, because it's a new connection!
465 */
466 be13::tcp_seq isn = syn_set ? seq : seq-1;
467 tcp = create_tcpip(this_flow, isn, pi);
468 }
469
470 /* Now tcp is valid */
471 tcp->myflow.tlast = pi.ts; // most recently seen packet
472 tcp->last_packet_number = packet_counter++;
473 tcp->myflow.len += pi.pcap_hdr->len;
474 tcp->myflow.caplen += pi.pcap_hdr->caplen;
475 tcp->myflow.packet_count++;
476
477 // Does not seem consitent => Print a notice
478 // See also https://stackoverflow.com/q/1491660
479 if(pi.pcap_hdr->caplen != pi.pcap_hdr->len){
480 DEBUG(2)("Captured packet has a length caplen=%d different "
481 "from the un-truncated length len=%d provided by PCAP API",
482 pi.pcap_hdr->caplen, pi.pcap_hdr->len);
483 }
484
485 /*
486 * 2012-10-24 slg - the first byte is sent at SEQ==ISN+1.
487 * The first byte in POSIX files have an LSEEK of 0.
488 * The original code overcame this issue by introducing an intentional off-by-one
489 * error with the statement tcp->isn++.
490 *
491 * With the new TCP state-machine we simply follow the spec.
492 *
493 * The new state machine works by examining the SYN and ACK packets
494 * in accordance with the TCP spec.
495 */
496 if(syn_set){
497 /* If the syn is set this is either a SYN or SYN-ACK. We use this information to set the direction
498 * flag, but that's it. The direction flag is only used for coloring.
499 */
500 if(tcp->syn_count>1){
501 DEBUG(2)("Multiple SYNs (%d) seen on connection %s",tcp->syn_count,tcp->flow_pathname.c_str());
502 }
503 tcp->syn_count++;
504 if( !ack_set ){
505 DEBUG(50) ("packet is handshake SYN"); /* First packet of three-way handshake */
506 tcp->dir = tcpip::dir_cs; // client->server
507 } else {
508 DEBUG(50) ("packet is handshake SYN/ACK"); /* second packet of three-way handshake */
509 tcp->dir = tcpip::dir_sc; // server->client
510 }
511 if(tcp_datalen>0){
512 tcp->violations++;
513 DEBUG(1) ("TCP PROTOCOL VIOLATION: SYN with data! (length=%d)",(int)tcp_datalen);
514 }
515 }
516 if(tcp_datalen==0) DEBUG(50) ("got TCP segment with no data"); // seems pointless to notify
517
518 /* process any data.
519 * Notice that this typically won't be called for the SYN or SYN/ACK,
520 * since they both have no data by definition.
521 */
522 if (tcp_datalen>0){
523 if (opt.console_output) {
524 tcp->print_packet(tcp_data, tcp_datalen);
525 } else {
526 if (opt.store_output){
527 tcp->store_packet(tcp_data, tcp_datalen, delta,pi.ts);
528 }
529 }
530 }
531
532 if (rst_set){
533 remove_flow(this_flow); // take it out of the map
534 return 0;
535 }
536
537 /* Count the FINs.
538 * If this is a fin, determine the size of the stream
539 */
540 if (fin_set){
541 tcp->fin_count++;
542 if(tcp->fin_count==1){
543 tcp->fin_size = (seq+tcp_datalen-tcp->isn)-1;
544 }
545 } else {
546 open_flows.move_to_end(tcp);
547 }
548
549 /* If a fin was sent and we've seen all of the bytes, close the stream */
550 DEBUG(50)("%d>0 && %d == %d",tcp->fin_count,tcp->seen_bytes(),tcp->fin_size);
551
552 if (tcp->fin_count>0 && tcp->seen_bytes() == tcp->fin_size){
553 DEBUG(50)("all bytes have been received; removing flow");
554 remove_flow(this_flow); // take it out of the map
555 }
556
557 DEBUG(50)("fin_set=%d seq=%u fin_count=%d seq_count=%d len=%d isn=%u",
558 fin_set,seq,tcp->fin_count,tcp->syn_count,(int)tcp_datalen,tcp->isn);
559 return 0; // successfully processed
560 }
561 #pragma GCC diagnostic warning "-Wcast-align"
562
563
564 /* This is called when we receive an IPv4 datagram. We make sure that
565 * it's valid and contains a TCP segment; if so, we pass it to
566 * process_tcp() for further processing.
567 *
568 * Note: we currently don't know how to handle IP fragments. */
569 #pragma GCC diagnostic ignored "-Wcast-align"
570
571
572
process_ip4(const be13::packet_info & pi)573 int tcpdemux::process_ip4(const be13::packet_info &pi)
574 {
575 /* make sure that the packet is at least as long as the min IP header */
576 if (pi.ip_datalen < sizeof(struct be13::ip4)) {
577 DEBUG(6) ("received truncated IP datagram!");
578 return -1; // couldn't process
579 }
580
581 const struct be13::ip4 *ip_header = (struct be13::ip4 *) pi.ip_data;
582
583 DEBUG(100)("process_ip4. caplen=%d vlan=%d ip_p=%d",(int)pi.pcap_hdr->caplen,(int)pi.vlan(),(int)ip_header->ip_p);
584 if(debug>200){
585 sbuf_t sbuf(pos0_t(),(const uint8_t *)pi.ip_data,pi.ip_datalen,pi.ip_datalen,false);
586 sbuf.hex_dump(std::cerr);
587 }
588
589 /* for now we're only looking for TCP; throw away everything else */
590 if (ip_header->ip_p != IPPROTO_TCP) {
591 DEBUG(50) ("got non-TCP frame -- IP proto %d", ip_header->ip_p);
592 return -1; // couldn't process
593 }
594
595 /* check and see if we got everything. NOTE: we must use
596 * ip_total_len after this, because we may have captured bytes
597 * beyond the end of the packet (e.g. ethernet padding).
598 */
599 size_t ip_len = ntohs(ip_header->ip_len);
600 if (pi.ip_datalen < ip_len) {
601 DEBUG(6) ("warning: captured only %ld bytes of %ld-byte IP datagram",
602 (long) pi.ip_datalen, (long) ip_len);
603 }
604
605 /* XXX - throw away everything but fragment 0; this version doesn't
606 * know how to do fragment reassembly.
607 */
608 if (ntohs(ip_header->ip_off) & 0x1fff) {
609 DEBUG(2) ("warning: throwing away IP fragment from X to X");
610 return -1;
611 }
612
613 /* figure out where the IP header ends */
614 size_t ip_header_len = ip_header->ip_hl * 4;
615
616 /* make sure there's some data */
617 if (ip_header_len > ip_len) {
618 DEBUG(6) ("received truncated IP datagram!");
619 return -1;
620 }
621
622 /* do TCP processing, faking an ipv6 address */
623 uint16_t ip_payload_len = ip_len - ip_header_len;
624 ipaddr src(ip_header->ip_src.addr);
625 ipaddr dst(ip_header->ip_dst.addr);
626 return process_tcp(src, dst, AF_INET,
627 pi.ip_data + ip_header_len, ip_payload_len,
628 pi);
629 }
630 #pragma GCC diagnostic warning "-Wcast-align"
631
632
633 /* This is called when we receive an IPv6 datagram.
634 *
635 * Note: we don't support IPv6 extended headers
636 */
637
638 /* These might be defined from an include file, so undef them to be sure */
639
process_ip6(const be13::packet_info & pi)640 int tcpdemux::process_ip6(const be13::packet_info &pi)
641 {
642 /* make sure that the packet is at least as long as the IPv6 header */
643 if (pi.ip_datalen < sizeof(struct be13::ip6_hdr)) {
644 DEBUG(6) ("received truncated IPv6 datagram!");
645 return -1;
646 }
647
648 const struct be13::ip6_hdr *ip_header = (struct be13::ip6_hdr *) pi.ip_data;
649
650 /* for now we're only looking for TCP; throw away everything else */
651 if (ip_header->ip6_ctlun.ip6_un1.ip6_un1_nxt != IPPROTO_TCP) {
652 DEBUG(50) ("got non-TCP frame -- IP proto %d", ip_header->ip6_ctlun.ip6_un1.ip6_un1_nxt);
653 return -1;
654 }
655
656 /* do TCP processing */
657 uint16_t ip_payload_len = ntohs(ip_header->ip6_ctlun.ip6_un1.ip6_un1_plen);
658 ipaddr src(ip_header->ip6_src.addr.addr8);
659 ipaddr dst(ip_header->ip6_dst.addr.addr8);
660
661 return process_tcp(src, dst ,AF_INET6,
662 pi.ip_data + sizeof(struct be13::ip6_hdr),ip_payload_len,pi);
663 }
664
665 /* This is called when we receive an IPv4 or IPv6 datagram.
666 * This function calls process_ip4 or process_ip6
667 * Returns 0 if packet is processed, 1 if it is not processed, -1 if error.
668 */
669
670 #pragma GCC diagnostic ignored "-Wcast-align"
process_pkt(const be13::packet_info & pi)671 int tcpdemux::process_pkt(const be13::packet_info &pi)
672 {
673 DEBUG(10)("process_pkt..............................................................................");
674 int r = 1; // not processed yet
675 switch(pi.ip_version()){
676 case 4:
677 r = process_ip4(pi);
678 break;
679 case 6:
680 r = process_ip6(pi);
681 break;
682 }
683 if(r!=0){ // packet not processed?
684 /* Write the packet if we didn't process it */
685 if(pwriter) pwriter->writepkt(pi.pcap_hdr,pi.pcap_data);
686 }
687
688 /* Process the timeout, if there is any */
689 if(tcp_timeout){
690 /* Get a list of the flows that need to be closed. */
691 std::vector<flow_addr *> to_close;
692 for(flow_map_t::iterator it = flow_map.begin(); it!=flow_map.end(); it++){
693 tcpip &tcp = *(it->second);
694 uint32_t age = pi.ts.tv_sec - tcp.myflow.tlast.tv_sec;
695 if (age > tcp_timeout){
696 to_close.push_back(&tcp.myflow);
697 }
698 }
699 /* Close them. This removes the flows from the flow_map(), which is why we need
700 * to create the list first.
701 */
702 for(std::vector<flow_addr *>::iterator it = to_close.begin(); it!=to_close.end(); it++){
703 remove_flow(*(*it));
704 }
705 }
706 return r;
707 }
708 #pragma GCC diagnostic warning "-Wcast-align"
709