📄 http_connect.c
字号:
/*http_connectCopyright July 5, 2001, The University of North Carolina at Chapel Hill All rights reserved. No part of this software may be sold ordistributed in any form or by any means without the prior writtenpermission of the Department of Computer Science, University of NorthCarolina at Chapel Hill. Distribution and use of this software issubject to the Software License Agreement incorporated in thissoftware. By having, retaining or using a copy of this software, youagree to be subject to the terms of the Software License Agreement.*******Software License AgreementPermission is given to copy http_connect, and its files (the Software)and to use them locally, as long as foregoing Copyright Notice is notremoved and the Software name is retained unaltered. By opening,possessing, retaining, using, or having a copy of the Software, youare deemed to have agreed to the terms of this Software LicenseAgreement.The Software is provided strictly on an "as is" basis without warrantyof any kind. Neither the University of North Carolina at ChapelHill, its faculty, staff or students, nor anyone else who has beeninvolved in the creation, production or delivery of the Softwareshall be liable for any direct, indirect, consequential or incidentaldamages arising out of the use or inability to use the Software evenif such entities or persons may be advised of the possibility of suchdamages.No part of this software may be sold or distributed in any form or byany means without the prior written permission of the Department ofComputer Science, University of North Carolina at Chapel Hill. Youruse of the Software is limited to non-commercial, not-for-profit usesand activities. To secure permission to make any other use of theSoftware, you should contact the person named below.Contact person: Frank D. Smith, University of North Carolina at Chapel Hill email: smithfd@cs.unc.edu phone: 919-962-1884 fax: 919-962-1799*//* This program performs an analysis of tcpdump output (the ASCII print lines that tcpdump generates to stdout) and produces a summary of the TCP connections used for HTTP. It assumes that the tcpdump has been filtered for packets that are from TCP source port 80 and that the result has been sorted so that packets are in ascending time order within each TCP connection. The script given below will properly prepare the input for this program given a tcpdump binary file that may contain more than just HTTP packets (the file extensions are just examples, the program does not make any assumptions about input file names). Note that this filtering produces a UNI-DIRECTIONAL trace containing only those TCP segments sent from the server to the client. The output is a file with summary records for each connection (basically the data data summarized into response and request lengths). There is also a <file name>.log file with summary counts. To get usage information, invoke the program with the -h switch. WARNING! THIS PROGRAM DEPENDS ON THE FORMAT OF THE OUTPUT OF TCPDUMP AS PRINTED ON STDOUT (ASCII). IT HAS BEEN TESTED ONLY ON THE FREEBSD VERSION OF TCPDUMP CORRESPONDING TO RELEASES UP THROUGH 4.1 KNOWN BUG: Does not process tcpdump output for ECN flags correctly.#! /bin/shtcpdump -n -tt -r $1 tcp src port 80 > $1.http-srvsort -s -o $1.http-srv-sort +1 -2 +3 -4 +0 -1 -T /tmp $1.http-srv*/#include <stdlib.h>#include <stdio.h>#include <math.h>#include <sys/time.h>#define min(a,b) ((a) <= (b) ? (a) : (b))#define max(a,b) ((a) >= (b) ? (a) : (b))int report_ACK_err = 1;void Usage(char *s){ fprintf (stderr,"\nUsage: %s\n", s); fprintf (stderr," [-w file_name] (name for output file)\n"); fprintf (stderr," [-r file_name] (name for input file)\n"); fprintf (stderr,"If either -w or -r is omitted, stdout(stdin) is used\n"); fprintf (stderr,"\n"); exit(-1);} FILE *dumpFP, *outFP; FILE *logFP; struct timeval recvTime; struct timeval lastTime = {0,0}; char ts[20]; /* ASCII timestamp in tcpdump output */ /* max. ssssssssss.mmmmmm characters + EOL */ char sh[25]; /* ASCII source host.port in tcpdump output */ /* max. hhh.hhh.hhh.hhh.ppppp + EOL */ char gt[3]; /* ">" symbol in tcpdump output */ char lt[3]; /* "<" symbol in tcpdump output */ char dh[25]; /* ASCII destination host.port in tcpdump output */ /* max. hhh.hhh.hhh.hhh.ppppp + EOL */ char fl[5]; /* ASCII TCP flags field in tcpdump output */ char p1[50]; /* ASCII first field after flags in tcpdump output */ char p2[50]; /* ASCII second field after flags */ char p3[50]; /* ASCII third field after flags *//* These are read from the tcpdump records */ unsigned long begin_seq, end_seq, seq_bytes, new_ack; unsigned long current_synseq; int has_seq, has_ack;/* In TCP ACKs should be monotonically increasing so the length of the current request in a sequence can be computed as the difference between the ACK value marking the end of the previous request and the ACK value marking the end of the current request. Unfortunately, out-of-order segments can cause ACKs to appear as if they "go backward". For segments without data (ACK_ONLY), simply ignoring the "backward" ACK is fine. In many cases where there is data along with a "backward" ACK, this is the result of (un-necessary) retransmission of segments containing data and those cases are handled properly. In other cases, the results can be incorrect for HTTP 1.1 connections. Each case of suspected ACK mis-ordering that might lead to erroneous request or response lengths is noted for off-line investigation. */ unsigned long current_request_end, last_request_end;/* In TCP segments the sequence numbers we see may NOT be monotonically increasing (retransmission, out-of-order). Instead we record the largest value seen at any point. Then the length of the current response in a sequence can be computed as the difference between the (largest) sequence at the end of the previous response and the (largest) sequence at the end of the current response. */ unsigned long current_response_end, last_response_end;/* Various counters for logging connection summary information */ int syn_count = 0; /* connections beginning with SYN in trace */ int req_count = 0; /* number of identified requests */ int rsp_count = 0; /* number of identified responses */ int fin_count = 0; /* connections ending with FIN in trace */ int rst_count = 0; /* connections ending with Reset (no FIN) */ int trm_count = 0; /* connections ending with no Reset or FIN */ int err_count = 0; /* connections with at least one suspected error */ int act_req_count = 0; /* connections beginning in a request */ int act_rsp_count = 0; /* connections beginning in a response */ int pending_fin_count = 0; /* partial with only FIN(s) */ int pending_rst_count = 0; /* partial with only Reset(s) */ int pending_ack_count = 0; /* partial with only ACK(s) */ int pending_oth_count = 0; /* partial -- others */ int pending_cmb_count = 0; /* partials with FIN, Reset, ACK combinations *//* Various counters for events within a single connection */ /* the following apply only when state == PENDING; see pending_xxx_counts above for explanations */ int have_pending_acks = 0; int have_pending_fins = 0; int have_pending_rsts = 0; int have_pending_othr = 0; /* the following apply only when state != PENDING */ int have_ACK_error = 0; /* seen "backwards" ACK */ int have_value_error = 0; /* seen suspect ACK or sequence # */ int have_FINdata_error = 0; /* seen data after FIN */ enum states {PENDING, SYN_SENT, FIN_SENT, RESET, IN_REQUEST, IN_RESPONSE}; enum states connection_state = PENDING; enum states last_state = PENDING; enum inputs {SYN, FIN, RST, ACK_ONLY, DATA_ACK}; enum inputs input_type; char current_src[25] = ""; char src_host[25]; char src_port[10]; char current_dst[25] = ""; char dst_host[25]; char dst_port[10];/* A request is considered to start at the timestamp on the tcpdump record containing the first advance in the ACK field (a) following the connection establishment or (b) while the connection is sending response data. */ char start_request_time[20];/* A response is considered to start at the timestamp on the tcpdump record containing the first advance in the sequence number field following a period when the ACK has been advanced (receiving request data). */ char start_response_time[20];/* A response is considered to end at the timestamp on the tcpdump record that LAST advanced the data sequence number before the response ends (a new request starts, a FIN is sent, etc.). Since we would have to look ahead in the trace to be sure the current record has the LAST advance, we go ahead and assume it is the last and record its timestamp as response_end_time. This way, when we know the sequence number will not advance more for this response from processsing some subsequent record in the trace (FIN or ACK advance), the last timestamp has already been saved. Similarly, a request is considered to end at the timestamp on the last record of the request. */ char response_end_time[20]; char request_end_time[20]; char FIN_sent_time[20]; char RST_sent_time[20]; char last_connection_time[20]; char input_name[256] = ""; char output_name[256] = ""; char log_name[256] = ""; char new_line[500]; /* assumes no tcpdump output line is longer */ long elapsed; int new_address = 0; int rc = 0;void error_line(char *s); void error_state(char *s);int parse_dump_record(void);void init_connection(void);void init_active(void);void check_tuple_reuse(void);int check_ACK_advance(unsigned long old_ack);void begin_REQ(void);void more_REQ(void);void begin_RSP(void);void more_RSP(void);void log_REQ(void);void log_RSP(void);void log_SYN(void);void log_END(char *how);void log_ACT(char *how);void log_nosyn(void);void log_connection(void);void log_log(void);long elapsed_ms(char *end, char *start);void get_host_port(char *adr, char *host, char *port);int get_sequence(char *p, unsigned long *begin, unsigned long *end, unsigned long *bytes);void main (int argc, char* argv[]){ int i; /* Parse the command line */ i = 1; while (i < argc) { if (strcmp (argv[i], "-r") == 0) { /* -r flag is followed by name of file to read */ if (++i >= argc) Usage (argv[0]); strcpy (input_name, argv[i]); } else if (strcmp (argv[i], "-w") == 0) { /* -w flag is followed by the name of file to write */ if (++i >= argc) Usage (argv[0]); strcpy (output_name, argv[i]); } else Usage (argv[0]); i++; } /* Open files */ /* Note: program is written to also be used as a filter */ if (strcmp(output_name, "") == 0) /* if no explicit output file named with -w, use stdout */ outFP = stdout; else { if ((outFP = fopen (output_name, "w")) == NULL) { fprintf (stderr, "error opening %s\n", output_name); exit (-1); } } if (strcmp(input_name, "") == 0) /* if no explicit input file named with -r, use stdin */ dumpFP = stdin; else { if ((dumpFP = fopen (input_name, "r")) == NULL) { fprintf (stderr, "error opening %s\n", input_name); exit (-1); } } strcpy(log_name, output_name); strcat(log_name, ".log"); if ((logFP = fopen (log_name, "w")) == NULL) { fprintf (stderr, "error opening %s\n", log_name); exit (-1); } /* begin main loop; once through loop for each line in the tcpdump */ /* a <continue> anywhere in the loop (usually after an error case) implies beginning of processing a new tcpdump record */ while (!feof (dumpFP)) {/* printf("State is %d, last_state is %d\n", connection_state, last_state); */ /* Get and parse line of tcpdump file */ fgets (new_line, sizeof(new_line), dumpFP); /* get line pieces; this works because there are always 8 or more fields separated by white space in tcpdump ASCII-format lines *//* sscanf (new_line, "%s %s %s %s %s %s %s %s %s", &ts, <, &sh, >, &dh, &fl, &p1, &p2, &p3);*/ sscanf (new_line, "%s %s %s %s %s %s %s %s", &ts, &sh, >, &dh, &fl, &p1, &p2, &p3); /* If any part of the connection tuple (source host.port,destination host.port) differs from the current values, there are no more tcpdump records for that connection so treat as end of connection. The action taken at the end of a connection depends on the current state of processing in that connection */ if ((strcmp(current_src, sh) != 0) || /* new source host/port */ (strcmp(current_dst, dh) != 0)) /* new dest. host/port */ { log_connection(); /* begin processing this record as being from a potential new TCP connection so initialize connection's state */ strcpy(current_src, sh); /* new connection tuple */ strcpy(current_dst, dh); /* host and port for src & dest */ have_pending_acks = 0; have_pending_fins = 0; have_pending_rsts = 0; have_pending_othr = 0; current_synseq = 0; connection_state = PENDING; /* unconnected pending a SYN */ last_state = PENDING; new_address = 1; /* true only for very first record from a different TCP connection -- avoids multiple error messages */ }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -