📄 hunt.c
字号:
/* * * This is free software. You can redistribute it and/or modify under * the terms of the GNU General Public License version 2. * * Copyright (C) 1998 by kra * */#include "hunt.h"#include <sys/types.h>#include <sys/time.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <signal.h>#include <unistd.h>#include <assert.h> /* * dont fragment with reset ??? */int linksock = -1;int mac_learn_from_ip = 0;int conn_list_mac = 0;int conn_list_seq = 0;struct hash conn_table;struct hash mac_table;int hunt_ready = 0;pthread_mutex_t mutex_hunt_ready = PTHREAD_MUTEX_INITIALIZER;pthread_cond_t cond_hunt_ready = PTHREAD_COND_INITIALIZER;/* * list of struct packet_info with information which packets skip in process * of updating connection */struct list l_skip_update = LIST_INIT(struct packet_info, next);/* * lists of functions which pass packets to modules */struct list l_ifunc_ip = LIST_INIT(struct ifunc_item, next_ip);struct list l_ifunc_tcp = LIST_INIT(struct ifunc_item, next_tcp);struct list l_ifunc_udp = LIST_INIT(struct ifunc_item, next_udp);struct list l_ifunc_icmp = LIST_INIT(struct ifunc_item, next_icmp);struct list l_ifunc_arp = LIST_INIT(struct ifunc_item, next_arp);struct list l_ifunc_fast_tcp = LIST_INIT(struct ifunc_item, next_tcp);/* * * packet operations * */static struct list l_packets = LIST_INIT(struct packet, p_next_free);int packets_allocated = 0;struct packet *packet_new(void){ struct packet *p; if (!(p = list_pop(&l_packets))) { if (!(p = malloc(sizeof(struct packet)))) { perror("malloc"); return NULL; } pthread_mutex_init(&p->p_mutex, NULL); p->p_use_count = 0; p->p_hdr.p_tcph = NULL; p->p_data = NULL; p->p_type = PACKET_NONE; p->p_ipc = 0; p->p_ipc_arg = NULL; packets_allocated++; } p->p_use_count = 1; return p;}void packet_copy_data(struct packet *dst, struct packet *src){ memcpy(dst->p_raw, src->p_raw, src->p_raw_len); dst->p_raw_len = src->p_raw_len; dst->p_type = src->p_type; dst->p_ethh = (struct ethhdr *)(dst->p_raw + ((char *)src->p_ethh - src->p_raw)); dst->p_iph = (struct iphdr *)(dst->p_raw + ((char *)src->p_iph - src->p_raw)); dst->p_arph = (struct arphdr *)(dst->p_raw + ((char *)src->p_arph - src->p_raw)); dst->p_hdr.p_tcph = (struct tcphdr *)(dst->p_raw + ((char *)src->p_hdr.p_tcph - src->p_raw)); dst->p_data_len = src->p_data_len; dst->p_data = dst->p_raw + (src->p_data - src->p_raw); memcpy(dst->p_arg, src->p_arg, sizeof(src->p_arg)); dst->p_ipc = src->p_ipc; dst->p_ipc_arg = src->p_ipc_arg;}void packet_free(struct packet *p){ int is_free; pthread_mutex_lock(&p->p_mutex); if (--p->p_use_count == 0) is_free = 1; else is_free = 0; pthread_mutex_unlock(&p->p_mutex); if (is_free) list_push(&l_packets, p);}void packet_want(struct packet *p){ pthread_mutex_lock(&p->p_mutex); ++p->p_use_count; pthread_mutex_unlock(&p->p_mutex);}void packet_flush(struct list *l){ struct packet *p; while ((p = list_pop(l))) packet_free(p);}void packet_preallocate(int count){ struct packet **p = alloca(count * sizeof(struct packet *)); int i; for (i = 0; i < count; i++) p[i] = packet_new(); for (i = 0; i < count; i++) packet_free(p[i]);}int packet_count(void){ return list_count(&l_packets);}/* * * TCP connection database * */static inline void fill_uci(struct user_conn_info *uci, struct packet *p){ uci->src_addr = p->p_iph->saddr; uci->dst_addr = p->p_iph->daddr; uci->src_port = p->p_hdr.p_tcph->source; uci->dst_port = p->p_hdr.p_tcph->dest;}#if 0static int ht_eq(unsigned int key, struct conn_info *c, struct packet *p){ if (c->src_addr == p->p_iph->saddr && c->dst_addr == p->p_iph->daddr && c->src_port == p->p_hdr.p_tcph->source && c->dst_port == p->p_hdr.p_tcph->dest) return 1; if (c->src_addr == p->p_iph->daddr && c->dst_addr == p->p_iph->saddr && c->src_port == p->p_hdr.p_tcph->dest && c->dst_port == p->p_hdr.p_tcph->source) return 1; return 0;}#endifstatic int ht_eq(unsigned int key, struct conn_info *c, struct user_conn_info *uci){ if (c->src_addr == uci->src_addr && c->dst_addr == uci->dst_addr && c->src_port == uci->src_port && c->dst_port == uci->dst_port) return 1; if (c->src_addr == uci->dst_addr && c->dst_addr == uci->src_addr && c->src_port == uci->dst_port && c->dst_port == uci->src_port) return 1; return 0;}void remove_conn_if_dont_match(void){ struct hash_iterator hi; struct conn_info *ci; unsigned int key; int count_to_remove = 0; unsigned int *key_to_remove; struct conn_info **ci_to_remove; hash_lock(&conn_table); count_to_remove = 0; key_to_remove = alloca(sizeof(unsigned int) * hash_count(&conn_table)); ci_to_remove = alloca(sizeof(struct conn_info *) * hash_count(&conn_table)); hash_iter_set(&hi, &conn_table); while ((ci = hash_iter_get(&hi, &key))) { if (!conn_add_match(ci->src_addr, ci->dst_addr, ci->src_port, ci->dst_port)) { ci_to_remove[count_to_remove] = ci; key_to_remove[count_to_remove++] = key; } } hash_iter_end(&hi); for ( ; count_to_remove >= 0; count_to_remove--) hash_remove(&conn_table, key_to_remove[count_to_remove], ci_to_remove[count_to_remove]); hash_unlock(&conn_table);}void conn_free(struct conn_info *ci){ int free_it; pthread_mutex_lock(&ci->mutex); if (--ci->use_count == 0) free_it = 1; else free_it = 0; pthread_mutex_unlock(&ci->mutex); if (free_it) free(ci);}struct conn_info *conn_get(struct user_conn_info *uci){ unsigned int key; struct conn_info *ci; key = uci_generate_key(uci); hash_lock(&conn_table); if ((ci = hash_get(&conn_table, key, uci))) { pthread_mutex_lock(&ci->mutex); ++ci->use_count; pthread_mutex_unlock(&ci->mutex); } hash_unlock(&conn_table); return ci;}int conn_exist(struct user_conn_info *uci){ unsigned int key; struct conn_info *ci; key = uci_generate_key(uci); if ((ci = hash_get(&conn_table, key, uci))) return 1; else return 0;}static int packet_match(struct packet_info *pi, struct packet *p){ struct iphdr *iph = p->p_iph; struct tcphdr *tcph = p->p_hdr.p_tcph; if (pi->src_addr == iph->saddr && pi->dst_addr == iph->daddr && pi->src_port == tcph->source && pi->dst_port == tcph->dest && pi->src.next_seq == tcph->seq && pi->src.next_d_seq == tcph->ack_seq && memcmp(pi->src.src_mac, p->p_ethh->h_source, ETH_ALEN) == 0 && memcmp(pi->src.dst_mac, p->p_ethh->h_dest, ETH_ALEN) == 0) return 1; else return 0;}static int conn_skip_update(struct conn_info *ci, struct packet *p){ struct list_iterator iter; struct packet_info *pi; list_iter_set(&iter, &l_skip_update); while ((pi = list_iter_get(&iter))) { if (packet_match(pi, p)) { list_iter_end(&iter); list_remove(&l_skip_update, pi); return 1; } } list_iter_end(&iter); return 0;}static void __conn_add(struct packet *p, unsigned int key){ struct iphdr *iph = p->p_iph; struct tcphdr *tcph = p->p_hdr.p_tcph; struct conn_info *ci; struct host_info *h_src, *h_dst; assert(ci = malloc(sizeof(struct conn_info))); memset(ci, 0, sizeof(struct conn_info)); ci->use_count = 1; pthread_mutex_init(&ci->mutex, NULL); if (ntohs(tcph->dest) >= 1024 && ntohs(tcph->source) < 1024) { ci->src_addr = iph->daddr; ci->dst_addr = iph->saddr; ci->src_port = tcph->dest; ci->dst_port = tcph->source; h_src = &ci->dst; h_dst = &ci->src; } else { ci->src_addr = iph->saddr; ci->dst_addr = iph->daddr; ci->src_port = tcph->source; ci->dst_port = tcph->dest; h_src = &ci->src; h_dst = &ci->dst; } h_src->next_seq = htonl(ntohl(tcph->seq) + p->p_data_len + tcph->syn ? 1 : 0); if (tcph->ack) h_src->next_d_seq = tcph->ack_seq; h_src->window = tcph->window; h_src->id = iph->id; memcpy(h_src->dst_mac, p->p_ethh->h_dest, ETH_ALEN); memcpy(h_src->src_mac, p->p_ethh->h_source, ETH_ALEN); /* guess or try to fill h_dst too */ h_dst->next_seq = h_src->next_d_seq; h_dst->next_d_seq = h_src->next_seq; h_dst->window = tcph->window; h_dst->id = iph->id; memcpy(h_dst->dst_mac, h_src->src_mac, ETH_ALEN); memcpy(h_dst->src_mac, h_src->dst_mac, ETH_ALEN); hash_put(&conn_table, key, ci);}static void ack_storm_notify(struct conn_info *ci, struct user_conn_info *uci){ struct timeval tv; int print_it = 0; if (!ci->ack_storm_notify_sec) { gettimeofday(&tv, NULL); print_it = 1; } else { gettimeofday(&tv, NULL); if (tv.tv_sec - ci->ack_storm_notify_sec >= 10) print_it = 1; } if (print_it) { set_tty_color(COLOR_BRIGHTRED); printf("\nhunt: possible ACK storm: "); print_user_conn_info(uci, 1); set_tty_color(COLOR_LIGHTGRAY); ci->ack_storm_notify_sec = tv.tv_sec; }}static void conn_add_update(struct packet *p){ static struct user_conn_info last_toadd = {0, 0, 0, 0}; static last_count = 0; unsigned int key; struct conn_info *ci; struct user_conn_info uci; unsigned int old_next_d_seq; fill_uci(&uci, p); key = uci_generate_key(&uci); hash_lock(&conn_table); if ((ci = hash_get(&conn_table, key, &uci)) && ht_eq(key, ci, &uci) == 1) { if (!conn_skip_update(ci, p)) { struct host_info *h_src, *h_dst; struct iphdr *iph = p->p_iph; struct tcphdr *tcph = p->p_hdr.p_tcph; if (ci->src_addr == iph->saddr && ci->dst_addr == iph->daddr && ci->src_port == tcph->source && ci->dst_port == tcph->dest) { h_src = &ci->src; h_dst = &ci->dst; } else { h_src = &ci->dst; h_dst = &ci->src; } old_next_d_seq = h_src->next_d_seq; h_src->next_seq = htonl(ntohl(tcph->seq) + p->p_data_len); if (tcph->ack) h_src->next_d_seq = tcph->ack_seq; h_src->id = iph->id; /* well, this should be in IP updater not in TCP */ h_src->window = tcph->window; /* well these can change too :-) */ memcpy(h_src->dst_mac, p->p_ethh->h_dest, ETH_ALEN); memcpy(h_src->src_mac, p->p_ethh->h_source, ETH_ALEN); /* * ACK storm detection */ h_src->delta_d_seq += ntohl(h_src->next_d_seq) - ntohl(old_next_d_seq); if (++ci->update_count % 400 == 0) { if (ci->src.delta_d_seq == 0 && ci->dst.delta_d_seq == 0) { ack_storm_notify(ci, &uci); } else { ci->src.delta_d_seq = 0; ci->dst.delta_d_seq = 0; } } } } else { /* test if we could add the connection */ if (p->p_data_len > 0) { /* * well, it contains data - add it */ if (conn_add_policy(p->p_iph, p->p_hdr.p_tcph)) __conn_add(p, key); } else { /* * well, check it this way because we don't want * to add RST, ACK to FIN, ... as connectinos. */ if ((last_toadd.src_addr == p->p_iph->saddr && last_toadd.dst_addr == p->p_iph->daddr && last_toadd.src_port == p->p_hdr.p_tcph->source && last_toadd.dst_port == p->p_hdr.p_tcph->dest) || (last_toadd.src_addr == p->p_iph->daddr && last_toadd.dst_addr == p->p_iph->saddr && last_toadd.src_port == p->p_hdr.p_tcph->dest && last_toadd.dst_port == p->p_hdr.p_tcph->source)) { if (++last_count >= 10) { last_count = 0; if (conn_add_policy(p->p_iph, p->p_hdr.p_tcph)) __conn_add(p, key); } } else { last_count = 0; last_toadd.src_addr = p->p_iph->saddr; last_toadd.dst_addr = p->p_iph->daddr; last_toadd.src_port = p->p_hdr.p_tcph->source; last_toadd.dst_port = p->p_hdr.p_tcph->dest; } } } hash_unlock(&conn_table);}static void conn_del(struct packet *p){ struct conn_info *ci; struct user_conn_info uci; unsigned int key; int remove_it = 0;#if 0 fill_uci(&uci, p); key = uci_generate_key(&uci); if ((ci = hash_remove(&conn_table, key, &uci))) { conn_free(ci); }#endif fill_uci(&uci, p); key = uci_generate_key(&uci); hash_lock(&conn_table); if ((ci = hash_get(&conn_table, key, &uci)) && ht_eq(key, ci, &uci) == 1) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -