📄 tcp.c
字号:
/* This file is part of sniffer, a packet capture utility and network moniter The author can be contacted at <mistral@stev.org> the lastest version is avilable from http://stev.org This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include <stdlib.h>#include <string.h>#include <errno.h>#include <pthread.h>#include <netinet/in.h>#include "config.h"#include "locks.h"#include "list.h"#include "log.h"#include "lookup.h"#include "stat.h"#include "ip.h"#include "in_ntoa.h"#include "tcp.h"#include "tcp_dump.h"#include "ftp.h"#include "http.h"#include "pop3.h"pthread_mutex_t tcp_mutex_slist = PTHREAD_MUTEX_INITIALIZER; /* lock for sorted list */pthread_mutex_t tcp_mutex_vlist = PTHREAD_MUTEX_INITIALIZER; /* lock for view list */pthread_mutex_t tcp_gui_mutex = PTHREAD_MUTEX_INITIALIZER;struct list_t *tcp_slist; /* sorted list */struct list_t *tcp_vlist; /* viewing list */struct gen_stat tcp_stat;WINDOW *tcp_gui_window;int tcp_timeout = TCP_TIMEOUT; /* 600 = 10 minutes this might need to be bigger */int tcp_cycle = TCP_CYCLE; /* how long it takes until we recycle a record */struct tcp_proto_t tcp_proto[] = { {21, ftp_init}, {80, http_init}, {110, pop3_init}, {0, NULL}};/****************************************************************************** TCP Packets *********************************************************************************************************/int tcp_handle(struct sniff_pkt *pkt, struct pkt_ip *ip, struct pkt_tcp *tcp) { void *pointer; struct tcp_data fake_data; /* this is used to search */ struct tcp_data *data; int index; unsigned short length; unsigned short port;#ifdef TCP_CHECKSUM char *ip_source, *ip_dest; unsigned short oldcheck;#endif pointer = (void *) tcp + (tcp->doff * 4); length = (ntohs(ip->tot_len) - (ip->ihl * 4) - (tcp->doff * 4)); tcp_stat.packets++; tcp_stat.bytes += length;#ifdef TCP_CHECKSUM oldcheck = tcp->check; tcp->check = 0; tcp->check = tcp_check(tcp, length + (tcp->doff * 4), ip->saddr, ip->daddr); if (oldcheck != tcp->check) { /* if these fail then they will contain null */ ip_source = lookup(ip->saddr); ip_dest = lookup(ip->daddr); log_error("FAILED TCP CHECKSUM: %s -> %s Packet: %u Sniffer: %u\n", ip_source, ip_dest, oldcheck, ip->check); tcp_stat.dropped++; return -1; }#endif tcp_gui_print(ip, tcp, length); /* search using in 1 direction */ fake_data.dest.ip = ip->daddr; fake_data.dest.port = tcp->dest; fake_data.src.ip = ip->saddr; fake_data.src.port = tcp->source; SLOCK(&tcp_mutex_slist); index = list_search(tcp_slist, &fake_data); if (index >= 0) { data = list_get(tcp_slist, index); data->src.stat.packets++; data->src.stat.bytes += length; memcpy(&data->src.head, tcp, sizeof(struct pkt_tcp)); tcp_set_state(data, &data->src); if (data->func_src) data->func_src(pkt, data, pointer, length); SUNLOCK(&tcp_mutex_slist); return -2; } /* now search in the other directorion */ fake_data.src.ip = ip->daddr; fake_data.src.port = tcp->dest; fake_data.dest.ip = ip->saddr; fake_data.dest.port = tcp->source; index = list_search(tcp_slist, &fake_data); if (index >= 0) { data = list_get(tcp_slist, index); data->dest.stat.packets++; data->dest.stat.bytes += length; memcpy(&data->dest.head, tcp, sizeof(struct pkt_tcp)); tcp_set_state(data, &data->dest); if (data->func_dst) data->func_dst(pkt, data, pointer, length); SUNLOCK(&tcp_mutex_slist); return -3; } /* if we get this far we need to create a new entry */ data = malloc(sizeof(struct tcp_data)); if (!data) { log_s("malloc failed"); SUNLOCK(&tcp_mutex_slist); return -4; } data->src.ip = ip->saddr; data->src.ip_str = in_ntoa(ip->saddr); data->src.ip_name = lookup(ip->saddr, 1); data->src.port = tcp->source; memcpy(&data->src.head, tcp, sizeof(struct pkt_tcp)); data->src.state = STCP_N; data->src.data_len = 0; init_stat(&data->src.stat, NULL); data->dest.ip = ip->daddr; data->dest.ip_str = in_ntoa(ip->daddr); data->dest.ip_name = lookup(ip->daddr, 1); data->dest.port = tcp->dest; bzero(&data->dest.head, sizeof(struct pkt_tcp)); data->dest.state = STCP_N; data->dest.data_len = 0; init_stat(&data->dest.stat, NULL); data->delme = 0; data->cycle = 0; data->timeout = time(NULL); data->dat = NULL; data->func_src = NULL; data->func_dst = NULL; data->func_cleanup = NULL; data->func_lookup = NULL; data->src.stat.packets++; data->src.stat.bytes += length; memcpy(&data->src.head, tcp, sizeof(struct pkt_tcp)); tcp_set_state(data, &data->src); index = 0; port = ntohs(tcp->dest); while(tcp_proto[index].init) { if (tcp_proto[index].port == port && tcp_proto[index].init) tcp_proto[index].init(data); index++; } if (data->func_src) data->func_src(pkt, data, pointer, length); list_add_sort(tcp_slist, data); SUNLOCK(&tcp_mutex_slist); SLOCK(&tcp_mutex_vlist); list_add(tcp_vlist, data); SUNLOCK(&tcp_mutex_vlist); return 0;} /* end of tcp_handle *//* this will se tthe state and the flags vars in the struct tcp_info */int tcp_set_state(struct tcp_data *dat, struct tcp_info *info) { dat->delme = 0; dat->timeout = time(NULL); dat->cycle = 0; /* do we have a SYN ? */ if (info->head.syn) { if (info->head.ack) { info->state = STCP_SYN_RECV; } else { info->state = STCP_SYN_SENT; } /* FIXME: Log funny packets ? */ return 0; } /* do we have a FIN ? */ if (info->head.fin) { if (info->head.ack) { info->state = STCP_FIN_WAIT1; return 0; } else { info->state = STCP_FIN_WAIT2; return 0; } } if (info->head.rst) { info->state = STCP_RESET; dat->delme = 1; return 0; } if (info->head.ack) { if (info->state == STCP_SYN_SENT && info->head.rst) { info->state = STCP_RESET; dat->delme = 1; return 0; } if (info->state == STCP_FIN_WAIT1 || info->state == STCP_FIN_WAIT2) { info->state = STCP_CLOSED; dat->delme = 1; return 0; } if (!info->head.fin) info->state = STCP_ESTABLISHED; return 0; } return 0;}/* lets tidy some stuff up */int tcp_tidy() { time_t ctime; int length; int i, max, tmp; struct tcp_data *data; time(&ctime); SLOCK(&tcp_mutex_vlist); length = list_length(tcp_vlist); for(i=0;i<length;i++) { data = list_get(tcp_vlist, i); if (data->delme) data->cycle++; if (data->timeout + tcp_timeout < ctime) data->delme = 1; if (data->cycle > tcp_cycle) { SLOCK(&tcp_mutex_slist); tmp = list_search(tcp_slist, data); if (tmp < 0) { log_s("oh dear i should have found a record to delete"); SUNLOCK(&tcp_mutex_slist); } else { list_del(tcp_slist, tmp); SUNLOCK(&tcp_mutex_slist); } list_del(tcp_vlist, i); if (data->func_cleanup) data->func_cleanup(data); if (data->src.ip_str) free(data->src.ip_str); if (data->dest.ip_str) free(data->dest.ip_str); free(data); } if (max >= 10) { max = 0; SUNLOCK(&tcp_mutex_vlist); SLOCK(&tcp_mutex_vlist); } length = list_length(tcp_vlist); max++; } SUNLOCK(&tcp_mutex_vlist); return 0;}int tcp_cmp(struct tcp_data *c1, struct tcp_data *c2) { if (c1->src.ip > c2->src.ip) return -1; if (c1->src.ip < c2->src.ip) return 1; if (c1->dest.ip > c2->dest.ip) return -1; if (c1->dest.ip < c2->dest.ip) return 1; if (c1->src.port > c2->src.port) return -1; if (c1->src.port < c2->src.port) return 1; if (c1->dest.port > c2->dest.port) return -1; if (c1->dest.port < c2->dest.port) return 1; return 0;}inline unsigned short tcp_check(struct pkt_tcp *th, unsigned short len, unsigned long saddr, unsigned long daddr) { unsigned long sum = 0; unsigned short *buff; buff = (unsigned short *) &saddr; sum += *buff++; sum += *buff; buff = (unsigned short *) &daddr; sum += *buff++; sum += *buff; sum += IP_TCP * 256; sum += htons(len) & 0xffff; buff = (unsigned short *) th; while(len > 1) { sum += *buff++; len -= 2; } if (len == 1) sum += (*buff & 0xff); sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); return ( (~sum) & 0xffff);}void tcp_gui_conn(struct gui_t *p, int y, int x) { int i, length, offset = 0, cury; WINDOW *draw; struct tcp_data *data; char *foot_back, buff[80]; draw = newwin(p->twin->_maxy - 1, p->twin->_maxx - 1, 1, 1); if (!draw) { log_s("newwin() failed"); return; } wbkgd(draw, COLOR_PAIR(COL_BACK)); foot_back = p->footer; while(1) { werase(draw); cury = 0; i = offset; if (offset > 0) mvwprintw(draw, 1, draw->_maxx - 12, "--more--"); /* we have the first 2 lines to play with the stats */ stat_process(&tcp_stat); snprintf(&buff[0], 80, "TCP Packets: %llu Dropped: %llu Data: %llu %s", tcp_stat.packets, tcp_stat.dropped, tcp_stat.readable, tcp_stat.messure); gui_footer(p, &buff[0]); SLOCK(&tcp_mutex_vlist); length = list_len(tcp_vlist); while(cury < draw->_maxy && i < length) { data = list_get(tcp_vlist, i); stat_process(&data->src.stat); stat_process(&data->dest.stat); if (data->src.ip_name) { mvwprintw(draw, cury++, 0, "/%s %24.24s [%u]\t%4lli:%llu %s\t%.0f:%.2f/Sec", tcp_gui_flags(&data->src), data->src.ip_name, ntohs(data->src.port), data->src.stat.packets, data->src.stat.readable, data->src.stat.messure, data->src.stat.rate_packets, data->src.stat.rate_kb); } else { mvwprintw(draw, cury++, 0, "/%s %24.24s [%u]\t%4lli:%llu %s\t%.0f:%.2f/Sec", tcp_gui_flags(&data->src), data->src.ip_str, ntohs(data->src.port), data->src.stat.packets, data->src.stat.readable, data->src.stat.messure, data->src.stat.rate_packets, data->src.stat.rate_kb); data->src.ip_name = lookup(data->src.ip, 1); } if (data->dest.ip_name) { mvwprintw(draw, cury++, 0, "\\%s %24.24s [%u]\t%4lli:%llu %s\t%.0f:%.2f/Sec", tcp_gui_flags(&data->dest), data->dest.ip_name, ntohs(data->dest.port), data->dest.stat.packets, data->dest.stat.readable, data->dest.stat.messure, data->dest.stat.rate_packets, data->dest.stat.rate_kb); } else { mvwprintw(draw, cury++, 0, "\\%s %24.24s [%u]\t%4lli:%llu %s\t%.0f:%.2f/Sec", tcp_gui_flags(&data->dest), data->dest.ip_str, ntohs(data->dest.port), data->dest.stat.packets, data->dest.stat.readable, data->dest.stat.messure, data->dest.stat.rate_packets, data->dest.stat.rate_kb); data->dest.ip_name = lookup(data->dest.ip, 1); } i++; } /* end of loop round the list_vlist */ SUNLOCK(&tcp_mutex_vlist); if (cury == 0) /* do we have any entries ? */ mvwprintw(draw, cury++, 0, " -- No Entries --"); else mvwprintw(draw, cury++, 0, " -- END --"); if (cury > draw->_maxy - 1) mvwprintw(draw, draw->_maxy , draw->_maxx - 8, "--more--"); wrefresh(draw); switch(gui_scroll(250, 0, length, &offset)) { case -1: /* error / timeout */ break; case 0: /* it did something */ break; default: goto get_out; break; } /* end of switch gui_utils_scroll */ } /* end while(1) */get_out: /* cleanup / quit */ gui_footer(p, foot_back); werase(draw); wrefresh(draw); delwin(draw); return;}void tcp_gui(struct gui_t *p, int y, int x) { WINDOW *draw; char *foot_back, buff[80]; SLOCK(&tcp_gui_mutex); draw = newwin(p->twin->_maxy - 1, p->twin->_maxx - 1, 1, 1); if (!draw) { log_s("subwin failed"); SUNLOCK(&tcp_gui_mutex); return; } wbkgd(draw, COLOR_PAIR(COL_BACK)); scrollok(draw, TRUE); werase(draw); wrefresh(draw); foot_back = p->footer; tcp_gui_window = draw; SUNLOCK(&tcp_gui_mutex); while (1) { if (gui_wait(250, 0) == 1) { switch(getch()) { default: goto get_out; break; } } else { stat_process(&tcp_stat); SLOCK(&tcp_gui_mutex); wrefresh(draw); snprintf(&buff[0], 80, "TCP Packets: %llu Data: %llu %s Drop: %llu", tcp_stat.packets, tcp_stat.readable, tcp_stat.messure, tcp_stat.dropped); gui_footer(p, &buff[0]); SUNLOCK(&tcp_gui_mutex); } }get_out: gui_footer(p, foot_back); SLOCK(&tcp_gui_mutex); tcp_gui_window = NULL; SUNLOCK(&tcp_gui_mutex); werase(draw); wrefresh(draw); delwin(draw); return;}inline int tcp_gui_print (struct pkt_ip *ip, struct pkt_tcp *tcp, unsigned short length) { if (!tcp_gui_window) return 0; SLOCK(&tcp_gui_mutex); gui_print(tcp_gui_window, "%s %s(%u) -> %s(%u) L:%u\n\tSEQ:%lu:%lu W:%u UP:%u\n", tcp_flags(tcp), lookup(ip->saddr, 0), ntohs(tcp->source), lookup(ip->daddr, 0), ntohs(tcp->dest), length, ntohl(tcp->seq), ntohl(tcp->ack_seq), ntohs(tcp->window), ntohs(tcp->urg_ptr)); SUNLOCK(&tcp_gui_mutex); return 0;}inline char *tcp_flags(struct pkt_tcp *tcp) { static char flags[9]; strcpy(&flags[0], "------\0"); /* we end a null */ if (tcp->syn) flags[0] = 'S'; if (tcp->fin) flags[1] = 'F'; if (tcp->rst) flags[2] = 'R'; if (tcp->urg) flags[3] = 'U'; if (tcp->ack) flags[4] = 'A'; if (tcp->psh) flags[5] = 'P'; return &flags[0];}inline char *tcp_gui_flags(struct tcp_info *cur) { static char flags[9]; bzero(&flags[0], 8); switch(cur->state) { case STCP_SYN_SENT: strcpy(&flags[0], "SSENT"); break; case STCP_SYN_RECV: strcpy(&flags[0], "SRECV"); break; case STCP_FIN_WAIT1: strcpy(&flags[0], "WAIT1"); break; case STCP_FIN_WAIT2: strcpy(&flags[0], "WAIT2"); break; case STCP_CLOSED: strcpy(&flags[0], "CLOSE"); break; case STCP_RESET: strcpy(&flags[0], "RESET"); break; default: strcpy(&flags[0], "-----\0"); /* we end a null */ if (cur->head.syn) flags[0] = 'S'; if (cur->head.fin) flags[1] = 'F'; if (cur->head.rst) flags[1] = 'R'; if (cur->head.urg) flags[2] = 'U'; if (cur->head.ack) flags[3] = 'A'; if (cur->head.psh) flags[4] = 'P'; break; } /* end of flags switch */ return flags;}/* lets setup a few things to get it working */int tcp_init() { SLOCK(&tcp_mutex_slist); tcp_slist = list_init(); list_setcmp(tcp_slist, (void *) tcp_cmp); SUNLOCK(&tcp_mutex_slist); SLOCK(&tcp_mutex_vlist); tcp_vlist = list_init(); SUNLOCK(&tcp_mutex_vlist); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -