📄 tcptable.c
字号:
* if the highlight bar is on either flow of the new connection. */ if (table->barptr == new_entry) { new_entry->starttime = time(NULL); new_entry->spanbr = 0; } else if (table->barptr == new_entry->oth_connection) { new_entry->oth_connection->starttime = time(NULL); new_entry->oth_connection->spanbr = 0; } /* * Add entries to hash table */ *nomem = add_tcp_hash_entry(table, new_entry); *nomem = add_tcp_hash_entry(table, new_entry->oth_connection); return new_entry;}void addtoclosedlist(struct tcptable *table, struct tcptableent *entry, int *nomem){ struct closedlist *ctemp; ctemp = malloc(sizeof(struct closedlist)); if (ctemp == NULL) { printnomem(); *nomem = 1; return; } /* * Point to closed entries */ ctemp->closedentry = entry; ctemp->pair = entry->oth_connection; entry->inclosed = entry->oth_connection->inclosed = 1; /* * Add node to closed entry list. */ if (table->closedtail != NULL) table->closedtail->next_entry = ctemp; table->closedtail = ctemp; table->closedtail->next_entry = NULL; if (table->closedentries == NULL) table->closedentries = ctemp;}char *tcplog_flowrate_msg(struct tcptableent *entry, struct OPTIONS *opts){ char rateunit[10]; float rate = 0; static char message[60]; time_t interval; interval = time(NULL) / (float) (entry->conn_starttime - time(NULL)); if (opts->actmode == KBITS) { strcpy(rateunit, "kbits/s"); if (interval > 0) rate = (float) (entry->bcount * 8 / 1000) / (float) interval; else rate = 0.00; } else { strcpy(rateunit, "kbytes/s"); if (interval > 0) rate = (float) (entry->bcount / 1024) / (float) interval; else rate = 0.00; } snprintf(message, 60, "avg flow rate %.2f %s", rate, rateunit); return message;}void write_timeout_log(int logging, FILE * logfile, struct tcptableent *tcpnode, struct OPTIONS *opts){ char msgstring[MSGSTRING_MAX]; if (logging) { snprintf(msgstring, MSGSTRING_MAX, "TCP; Connection %s:%s to %s:%s timed out, %lu packets, %lu bytes, %s; opposite direction %lu packets, %lu bytes, %s", tcpnode->s_fqdn, tcpnode->s_sname, tcpnode->d_fqdn, tcpnode->d_sname, tcpnode->pcount, tcpnode->bcount, tcplog_flowrate_msg(tcpnode, opts), tcpnode->oth_connection->pcount, tcpnode->oth_connection->bcount, tcplog_flowrate_msg(tcpnode->oth_connection, opts)); writelog(logging, logfile, msgstring); }}struct tcptableent *in_table(struct tcptable *table, unsigned long saddr, unsigned long daddr, unsigned int sport, unsigned int dport, char *ifname, int logging, FILE * logfile, int *nomem, struct OPTIONS *opts){ struct tcp_hashentry *hashptr; unsigned int hp; int hastimeouts = 0; time_t now; time_t timeout; if (opts != NULL) timeout = opts->timeout; else timeout = 0; if (table->head == NULL) { return 0; } /* * Determine hash table index for this set of addresses and ports */ hp = tcp_hash(saddr, sport, daddr, dport, ifname); hashptr = table->hash_table[hp]; while (hashptr != NULL) { if ((hashptr->tcpnode->saddr.s_addr == saddr) && (hashptr->tcpnode->daddr.s_addr == daddr) && (hashptr->tcpnode->sport == sport) && (hashptr->tcpnode->dport == dport) && (strcmp(hashptr->tcpnode->ifname, ifname) == 0)) break; now = time(NULL); /* * Add the timed out entries to the closed list in case we didn't * find any closed ones. */ if ((timeout > 0) && ((now - hashptr->tcpnode->lastupdate) / 60 > timeout) && (!(hashptr->tcpnode->inclosed))) { hashptr->tcpnode->timedout = 1; hashptr->tcpnode->oth_connection->timedout = 1; addtoclosedlist(table, hashptr->tcpnode, nomem); if (!(*nomem)) hastimeouts = 1; if (logging) write_timeout_log(logging, logfile, hashptr->tcpnode, opts); } hashptr = hashptr->next_entry; } if (hashptr != NULL) { /* needed to avoid SIGSEGV */ if ((((hashptr->tcpnode->finsent == 2) && (hashptr->tcpnode->oth_connection->finsent == 2))) || (((hashptr->tcpnode->stat & FLAG_RST) || (hashptr->tcpnode->oth_connection->stat & FLAG_RST)))) { return NULL; } else { return hashptr->tcpnode; } } else { return NULL; }} /* * Update the TCP status record should an applicable packet arrive. */void updateentry(struct tcptable *table, struct tcptableent *tableentry, struct tcphdr *transpacket, char *packet, int linkproto, unsigned long packetlength, unsigned int bcount, unsigned int fragofs, int logging, int *revlook, int rvnfd, struct OPTIONS *opts, FILE * logfile, int *nomem){ char msgstring[MSGSTRING_MAX]; char newmacaddr[15]; if (tableentry->s_fstat != RESOLVED) { tableentry->s_fstat = revname(revlook, &(tableentry->saddr), tableentry->s_fqdn, rvnfd); strcpy(tableentry->oth_connection->d_fqdn, tableentry->s_fqdn); tableentry->oth_connection->d_fstat = tableentry->s_fstat; } if (tableentry->d_fstat != RESOLVED) { tableentry->d_fstat = revname(revlook, &(tableentry->daddr), tableentry->d_fqdn, rvnfd); strcpy(tableentry->oth_connection->s_fqdn, tableentry->d_fqdn); tableentry->oth_connection->s_fstat = tableentry->d_fstat; } tableentry->pcount++; tableentry->bcount += bcount; tableentry->psize = packetlength; tableentry->spanbr += bcount; if (opts->mac) { bzero(newmacaddr, 15); if ((linkproto == LINK_ETHERNET) || (linkproto == LINK_PLIP)) { convmacaddr(((struct ethhdr *) packet)->h_source, newmacaddr); } else if (linkproto == LINK_FDDI) { convmacaddr(((struct fddihdr *) packet)->saddr, newmacaddr); } else if (linkproto == LINK_TR) { convmacaddr(((struct trh_hdr *) packet)->saddr, newmacaddr); } if (tableentry->smacaddr[0] != '\0') { if (strcmp(tableentry->smacaddr, newmacaddr) != 0) { snprintf(msgstring, MSGSTRING_MAX, "TCP; %s; from %s:%s to %s:%s: new source MAC address %s (previously %s)", tableentry->ifname, tableentry->s_fqdn, tableentry->s_sname, tableentry->d_fqdn, tableentry->d_sname, newmacaddr, tableentry->smacaddr); writelog(logging, logfile, msgstring); strcpy(tableentry->smacaddr, newmacaddr); } } else strcpy(tableentry->smacaddr, newmacaddr); } /* * If this is not the first TCP fragment, skip interpretation of the * TCP header. */ if ((ntohs(fragofs) & 0x1fff) != 0) { tableentry->lastupdate = tableentry->oth_connection->lastupdate = time(NULL); return; } /* * At this point, we have a TCP header, and we proceed to process it. */ if (tableentry->pcount == 1) { if ((transpacket->syn) || (transpacket->rst)) tableentry->partial = 0; else tableentry->partial = 1; } tableentry->win = ntohs(transpacket->window); tableentry->stat = 0; if (transpacket->syn) tableentry->stat |= FLAG_SYN; if (transpacket->ack) { tableentry->stat |= FLAG_ACK; /* * The following sequences are used when the ACK is in response to * a FIN (see comments for FIN below). If the opposite direction * already has its indicator set to 1 (FIN sent, not ACKed), and * the incoming ACK has the same sequence number as the previously * stored FIN's ack number (i.e. the ACK in response to the opposite * flow's FIN), the opposite direction's state is set to 2 (FIN sent * and ACKed). */ if ((tableentry->oth_connection->finsent == 1) && (ntohl(transpacket->seq) == tableentry->oth_connection->finack)) { tableentry->oth_connection->finsent = 2; if (logging) { writetcplog(logging, logfile, tableentry, tableentry->psize, opts->mac, "FIN acknowleged"); } } } /* * The closing sequence is similar, but not identical to the TCP close * sequence described in the RFC. This sequence is primarily cosmetic. * * When a FIN is sent in a direction, a state indicator is set to 1, * to indicate a FIN sent, but not ACKed yet. For comparison later, * the acknowlegement number is also saved in the entry. See comments * in ACK above. */ if (transpacket->fin) { /* * First, we check if the opposite direction has no counts, in which * case we simply mark the entire connection available for reuse. * This is in case packets from a machine pass an interface, but * on the return, completely bypasses any interface on our machine. * * Q: Could such a situation really happen in practice? I managed to * do it but under *really* ridiculous circumstances. * * A: (as of version 2.5.0, June 2001): Yes this DOES happen in * practice. Unidirectional satellite feeds can send data straight * to a remote network using you as your upstream. */ if (tableentry->oth_connection->pcount == 0) addtoclosedlist(table, tableentry, nomem); else { /* * That aside, mark the direction as being done, and make it * ready for a complete close upon receipt of an ACK. We save * the acknowlegement number for identification of the proper * ACK packet when it arrives in the other direction. */ tableentry->finsent = 1; tableentry->finack = ntohl(transpacket->ack_seq); } if (logging) { sprintf(msgstring, "FIN sent; %lu packets, %lu bytes, %s", tableentry->pcount, tableentry->bcount, tcplog_flowrate_msg(tableentry, opts)); writetcplog(logging, logfile, tableentry, tableentry->psize, opts->mac, msgstring); } } if (transpacket->rst) { tableentry->stat |= FLAG_RST; if (!(tableentry->inclosed)) addtoclosedlist(table, tableentry, nomem); if (logging) { snprintf(msgstring, MSGSTRING_MAX, "Connection reset; %lu packets, %lu bytes, %s; opposite direction %lu packets, %lu bytes; %s", tableentry->pcount, tableentry->bcount, tcplog_flowrate_msg(tableentry, opts), tableentry->oth_connection->pcount, tableentry->oth_connection->bcount, tcplog_flowrate_msg(tableentry->oth_connection, opts)); writetcplog(logging, logfile, tableentry, tableentry->psize, opts->mac, msgstring); } } if (transpacket->psh) tableentry->stat |= FLAG_PSH; if (transpacket->urg) tableentry->stat |= FLAG_URG; tableentry->lastupdate = tableentry->oth_connection->lastupdate = time(NULL); /* * Shall we add this entry to the closed entry list? If both * directions have their state indicators set to 2, or one direction * is set to 2, and the other 1, that's it. */ if ((!tableentry->inclosed) && (((tableentry->finsent == 2) && ((tableentry->oth_connection->finsent == 1) || (tableentry->oth_connection->finsent == 2))) || ((tableentry->oth_connection->finsent == 2) && ((tableentry->finsent == 1) || (tableentry->finsent == 2))))) addtoclosedlist(table, tableentry, nomem);}/* * Clears out the resolved IP addresses from the window. This prevents * overlapping port numbers (in cases where the resolved DNS name is shorter * than its IP address), that may cause the illusion of large ports. Plus, * such output, while may be interpreted by people with a little know-how, * is just plain wrong. * * Returns immediately if the entry is not visible in the window. */void clearaddr(struct tcptable *table, struct tcptableent *tableentry, unsigned int screen_idx){ unsigned int target_row; if ((tableentry->index < screen_idx) || (tableentry->index > screen_idx + (table->imaxy - 1))) return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -