📄 http_connect.c
字号:
/* break dump record into essential data fields; initializes the following variables: begin_seq, end_seq, seq_bytes, new_ack, has_ack, has_seq, input_type. Also checks for suspect sequence and ACK values. */ if ((rc = parse_dump_record()) < 0) continue; /* processing records from a TCP connections is based on a notion of the current "state" of the connection. The defined states are PENDING := record is from different connection than before but a beginning SYN has not yet been identified. SYN_SENT:= have identified SYN sent from source port 80 (server) FIN_SENT:= have identified a FIN sent from source port 80 (server) This terminates any data from server. RESET := have identified a Reset sent from source port 80 (server) This means that the server should not accept any more client data. IN_REQUEST := processing ACKs sent from source port 80 (server) in response to data (request) from the client. In this state, need to identify end of client data (request) and start of server data (response). IN_RESPONSE := processing data sequence #s from source port 80 In this state, need to identify the end of server data (response) and, possibly the beginning of a new request. Whenever the state changes, the prior state is also noted. Fundamental to all of this is the notion that a server cannot possibly be sending data in response to a request unless that data is accompanied or preceeded by an advance in the ACK sequence indicating receipt of the request data. Similarly, we assume that any new data sent by a server that follows or is accompanied by an advance in the ACK sequence number is a response to the request that caused the ACK sequence to advance. Put another way, response data (sequence # advance) marks the end of a request and ACK advance marks the end of a response. Of course other events such as FIN or Reset can mark ends also. The use of ACK advance to mark the end of a response assumes that HTTP/1.1 browsers don't overlap requests on a single TCP connection even if they may "batch" requests, i.e., a new request will not be generated until the response has been received. If requests and responses are batched but not overlapped this will understate the number of objects requested and overstate request and response sizes. This use of advancing sequence numbers (ACK or data) to mark requests and responses is disturbed by segment reorderings in the network. In some cases, such as reordering of only data segments in a response, there is no problem since only the highest value seen is used. Reordering of ACKs (especially with data) presents real problems since boundaries between requests and responses are missed which can result in overstating request and response sizes. For this reason, all such cases of ACK misordering are logged and reported. */ switch (connection_state) /* a <break> anywhere ends processing of the current tcpdump record by ending the switch (which continues the main read loop) */ { case PENDING: { switch (input_type) { case FIN: { /* Ignore random FIN before something useful */ have_pending_fins++; break; } case SYN: { /* normal connection start, initialize connection state */ init_connection(); break; } case RST: { /* Ignore random Reset before something useful */ have_pending_rsts++; break; } /* The trace may start after a connection is established and we do not see a SYN. Determine if the connection is most likely in a request or in a response and log its status. As before, a request is indicated if the ACK sequence (after the first one in the trace) is advancing and a response is indicated if the data sequence number is advancing. */ case ACK_ONLY: { /* ignore initial ACK (has absolute value, not relative) */ if (new_address == 1) { new_address = 0; have_pending_acks++; } else { /* If ACK advances, the connection is in a request */ if ((new_ack > 2) && (new_ack < 16384)) { log_ACT("REQ"); last_request_end = 1; current_request_end = new_ack; last_response_end = 1; current_response_end = 1; /* record the request start time as beginning at the tcpdump time stamp on this record */ strcpy(start_request_time, ts); strcpy(request_end_time, ts); last_state = connection_state; connection_state = IN_REQUEST; init_active(); /* initialize connection state */ } else /* ignore ACKs that are not advancing */ have_pending_acks++; } break; } case DATA_ACK: { /* If data sequence advances, connection is in response */ if ((seq_bytes > 1) && (seq_bytes < 65535)) { log_ACT("RSP"); /* assume tcpdump relative addressing and initialize */ last_request_end = 1; current_request_end = 1; last_response_end = 0; current_response_end = seq_bytes; /* record timestamp of tcpdump record as current value of both start and end times of response (in case no later end time is found) */ strcpy(start_response_time, ts); strcpy(response_end_time, ts); last_state = connection_state; connection_state = IN_RESPONSE; init_active(); } else /* ignore data lengths of 0 or 1 */ have_pending_othr++; break; } default: break; } /* end switch on input_type */ break; } /* end case PENDING */ case SYN_SENT: { /* Treat this case as the establishment of a connection. Usually the first activity on the connection will be request data from the client, but some servers appear to "pre-send" data (maybe the headers) speculatively before ACKing any client data. */ switch (input_type) { case FIN: /* A FIN marks the end of either or both request and response */ { if ((has_ack == 1) && (new_ack > (current_request_end + 1))) /* ignore possible ACK of FIN */ { /* this record had advanced the ACK sequence so save current request data and log it (since the FIN ends the connection it also ends the request). */ begin_REQ(); log_REQ(); } /* If the data sequence number advances, then there was response data. Save the current response info. and log it (since the FIN ends the connection, it also ends the response). */ if ((has_seq == 1) && (end_seq > current_response_end)) { begin_RSP(); log_RSP(); } last_state = SYN_SENT; connection_state = FIN_SENT; /* record timestamp of first FIN seen on connection */ if (strcmp(FIN_sent_time, "") == 0) strcpy(FIN_sent_time, ts); break; } case SYN: { /* In some cases the same host/port pairs are reused in a single trace; check for plausible reuse */ check_tuple_reuse(); break; } case RST: { connection_state = RESET; last_state = SYN_SENT; /* record timestamp of first Reset on the connection */ if (strcmp(RST_sent_time, "") == 0) strcpy(RST_sent_time, ts); break; } case ACK_ONLY: { /* since there is no data sequence # present in the record and, therefore, the server is not sending data so all the client's data may not have arrived. Note the current extent of ACKed client data and change state */ if (new_ack > (current_request_end + 1)) begin_REQ(); break; } case DATA_ACK: { /* check for presence of data sequence # in the common cases in SYN_SENT state, data presence indicates that request data has been received and server is sending data that should be a response */ if (new_ack > (current_request_end + 1)) {/* this record had advanced the ACK sequence so save current request info. and change state */ begin_REQ(); /* the server's data sequence may not have advanced; but if it has, treat it as the start of a response and the end of the client (request) data */ if (end_seq > current_response_end) { /* start of response ends the request, log it and change state to look for end of response */ log_REQ(); begin_RSP(); } } else /* some servers appear to send response data immediately on completing the TCP connection without receiving any request data */ if ((end_seq > last_response_end) && (seq_bytes > 0)) begin_RSP(); break; } default: break; } /* end switch on input type */ break; } /* end case SYN_SENT */ case FIN_SENT: { switch (input_type) { case SYN: { /* In some cases the same host/port pairs are reused in a single trace; check for plausible reuse */ check_tuple_reuse(); break; } case FIN: /* ignore multiple FINs */ break; case RST: /* ignore reset after FIN */ break; case ACK_ONLY: /* If there is an ACK (only) coming after a FIN is sent, it is ether the normal one in the 4-way termination or it is to ACK more request data which will be ignored (there can be no response). In either case, it is ignored here. */ break; case DATA_ACK: { /* All others may have sequence number fields. Treat them as errors if they advance the sequence number after a FIN. The usual case here is just retransmissions (including retransmission of the FIN) which should not advance it because the highest sequence number possible was on the FIN */ if ((end_seq > (current_response_end + 2)) && (have_FINdata_error == 0)) { error_state("new data in FIN_SENT state"); have_FINdata_error = 1; } break; } default: break; } /* end switch on input type */ break; } /* end case FIN_SENT */ case RESET: { /* A Reset nominally means an abnormal close of the connection with any queued data discarded before transmitting it. We observe, however, that under some (unknown) circumstances segments that advance the data sequence number continue in the trace after the Reset. If these are part of a response, it makes sense to count them in the response size since the server obviously sent them and the network has to handle them. This also means that a FIN following the Reset may be a valid indication of the end of a response. Just ignore anything else unexpected (e.g., Reset) */ switch (input_type) { case RST:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -