📄 icmp.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 <stdio.h>#include <stdlib.h>#include <errno.h>#include <pthread.h>#include <string.h>#include <sys/socket.h>#include <sys/types.h>#include <netinet/in.h>#include "config.h"#include "sniff.h"#include "locks.h"#include "list.h"#include "log.h"#include "stat.h"#include "lookup.h"#include "in_ntoa.h"#include "ip.h"#include "udp.h"#include "tcp.h"#include "icmp.h"struct list_t *icmp_type;struct list_t *icmp_unreach;struct list_t *icmp_redirect;struct list_t *icmp_ttl;struct list_t *icmp_param;struct gen_stat icmp_stat;WINDOW *icmp_gui_window = NULL;pthread_mutex_t icmp_gui_mutex = PTHREAD_MUTEX_INITIALIZER;FILE *icmp_log;/****************************************************************************** ICMP Packets ********************************************************************************************************/int icmp_handle(struct sniff_pkt *pkt, struct pkt_ip *ip, struct pkt_icmp *icmp) { char *ip_source = NULL, *ip_dest = NULL; unsigned short length; struct icmp_type_t search_type, *type = NULL; int i;#ifdef ICMP_CHECKSUM unsigned short checksum;#endif pkt->func = "icmp_handle"; if (pkt->dataleft < sizeof(struct pkt_icmp)) { icmp_stat.dropped++; return ERR_DATA; } pkt->dataleft -= sizeof(struct pkt_icmp); /* find out how much data we have */ length = ntohs(ip->tot_len) - (ip->ihl * 4) - sizeof(struct pkt_icmp); icmp_stat.packets++; icmp_stat.bytes += length; ip_source = lookup(ip->saddr, 0); ip_dest = lookup(ip->daddr, 0);#ifdef ICMP_CHECKSUM checksum = icmp->check; icmp->check = 0; /* we need to remember to add the icmp header length on */ icmp->check = ip_cksum( (void *) icmp, length + 8); if (icmp->check != checksum) { /* it failed */ log_error("Failed ICMP Checksum %s -> %s\n", ip_source, ip_dest); icmp_stat.dropped++; return ERR_CSUM; }#endif search_type.type = icmp->type; i = list_search(icmp_type, &search_type); /* we have a type we know about */ /* lets see if we have a code we know about */ type = list_get(icmp_type, i); if (!type) return icmp_log_any(pkt, ip_source, ip_dest, ip, icmp); if (type->code) return icmp_log_code(pkt, ip_source, ip_dest, type, ip, icmp); return icmp_log_type(pkt, ip_source, ip_dest, type, ip, icmp);}inline int icmp_log_any (struct sniff_pkt *pkt, char *ip_source, char *ip_dest, struct pkt_ip *ip, struct pkt_icmp *icmp) { int len = pkt->dataleft + sizeof(struct pkt_icmp); if (icmp_log) fprintf(icmp_log, "%s %s -> %s L:%u T:%.2X TTL:%u Type: 0x%.2X Code: 0x%.2X\n", pkt->if_name, ip_source, ip_dest, len, ip->tos, ip->ttl, icmp->type, icmp->code); return icmp_gui_print("%s %s -> %s L:%u T:%.2X TTL:%u Type: 0x%.2X Code: 0x%.2X\n", pkt->if_name, ip_source, ip_dest, len, ip->tos, ip->ttl, icmp->type, icmp->code);}inline int icmp_log_type(struct sniff_pkt *pkt, char *ip_source, char *ip_dest, struct icmp_type_t *type, struct pkt_ip *ip, struct pkt_icmp *icmp) { int len = pkt->dataleft + sizeof(struct pkt_icmp); char buff[100]; if (type->func) { buff[0] = (char ) NULL; type->func(pkt, &buff[0], sizeof(buff), ip, icmp); if (type->log && icmp_log) fprintf(icmp_log, "%s %s -> %s L:%u T:%.2X TTL:%u %s %s\n", pkt->if_name, ip_source, ip_dest, len, ip->tos, ip->ttl, type->desc, &buff[0]); return icmp_gui_print("%s %s -> %s L:%u T:%.2X TTL:%u %s %s\n", pkt->if_name, ip_source, ip_dest, len, ip->tos, ip->ttl, type->desc, &buff[0]); } if (type->log &&icmp_log) fprintf(icmp_log, "%s %s -> %s L:%u T:%.2X TTL:%u %s\n", pkt->if_name, ip_source, ip_dest, len, ip->tos, ip->ttl, type->desc); return icmp_gui_print("%s %s -> %s L:%u T:%.2X TTL:%u %s\n", pkt->if_name, ip_source, ip_dest, len, ip->tos, ip->ttl, type->desc);}inline int icmp_log_code(struct sniff_pkt *pkt, char *ip_source, char *ip_dest, struct icmp_type_t *type, struct pkt_ip *ip, struct pkt_icmp *icmp) { int len = pkt->dataleft + sizeof(struct pkt_icmp); struct icmp_code_t search, *code; char buff[100]; int i; search.code = icmp->code; i = list_search(type->code, &search); code = list_get(type->code, i); if (!code) return icmp_log_type(pkt, ip_source, ip_dest, type, ip, icmp); if (code->func) { buff[0] = (char ) NULL; code->func(pkt, &buff[0], sizeof(buff), ip, icmp); if (code->log && icmp_log) fprintf(icmp_log, "%s %s -> %s L:%u T:%.2X TTL:%u %s %s %s\n", pkt->if_name, ip_source, ip_dest, len, ip->tos, ip->ttl, type->desc, code->desc, &buff[0]); return icmp_gui_print("%s %s -> %s L:%u T:%.2X TTL:%u %s %s %s\n", pkt->if_name, ip_source, ip_dest, len, ip->tos, ip->ttl, type->desc, code->desc, &buff[0]); } if (code->log && icmp_log) fprintf(icmp_log, "%s %s -> %s L:%u T:%.2X TTL:%u %s %s\n", pkt->if_name, ip_source, ip_dest, len, ip->tos, ip->ttl, type->desc, code->desc); return icmp_gui_print("%s %s -> %s L:%u T:%.2X TTL:%u %s %s\n", pkt->if_name, ip_source, ip_dest, len, ip->tos, ip->ttl, type->desc, code->desc);}int icmp_ping(struct sniff_pkt *pkt, char *buf, int buffleft, struct pkt_ip *ip, struct pkt_icmp *icmp) { snprintf(buf, buffleft, "ID: %u SEQ: %u", icmp->un.echo.id, icmp->un.echo.sequence); return 0;}int icmp_ping_reply(struct sniff_pkt *pkt, char *buf, int buffleft, struct pkt_ip *ip, struct pkt_icmp *icmp) { snprintf(buf, buffleft, "ID: %u SEQ: %u", icmp->un.echo.id, icmp->un.echo.sequence); return 0;}int icmp_do(struct sniff_pkt *pkt, char *buf, int buffleft, struct pkt_ip *ip, struct pkt_icmp *icmp) { return icmp_proto(pkt, buf, buffleft, ip, icmp);}int icmp_proto(struct sniff_pkt *pkt, char *buf, int buffleft, struct pkt_ip *ip, struct pkt_icmp *icmp) { struct pkt_ip *encap_ip; struct pkt_icmp *encap_icmp; struct pkt_udp *encap_udp; struct pkt_tcp *encap_tcp; char flags[9]; void *pointer; /* next pointer */ char *ip_source, *ip_dest; int ilen, i; encap_ip = (struct pkt_ip *) ((void *) icmp + (sizeof(struct pkt_icmp))); if (encap_ip->version != 4) return snprintf(buf, buffleft, "\n\tIncorrect IP version %d should be 4", encap_ip->version); if (encap_ip->ihl < 5) return snprintf(buf, buffleft, "\n\tInvalid header length value"); ilen = encap_ip->ihl * 4; pointer = (void *) ( (void *) encap_ip + ilen); if (pkt->dataleft < ilen) return snprintf(buf, buffleft, "\n\tNot enough data"); pkt->dataleft -= ilen; ip_source = lookup(encap_ip->saddr, 0); ip_dest = lookup(encap_ip->daddr, 0); i = snprintf(buf, buffleft, "\n\tL:%u T:%.2X TTL:%u ", ntohs(encap_ip->tot_len), encap_ip->tos, encap_ip->ttl); buffleft -= i; buf += i; switch(encap_ip->protocol) { case IP_ICMP: if (pkt->dataleft < sizeof(struct pkt_icmp)) return snprintf(buf, buffleft, "ICMP %s -> %s ICMP Out of Data", ip_source, ip_dest); encap_icmp = pointer; return snprintf(buf, buffleft, "ICMP %s -> %s Type: %u Code: %u", ip_source, ip_dest, encap_icmp->type, encap_icmp->code); break; case IP_TCP: if (pkt->dataleft < sizeof(struct pkt_tcp)) return snprintf(buf, buffleft, "TCP %s -> %s Out of data", ip_source, ip_dest); encap_tcp = pointer; strcpy(&flags[0], "------\0\0"); /* we end a null */ if (encap_tcp->syn) flags[0] = 'S'; if (encap_tcp->fin) flags[1] = 'F'; if (encap_tcp->rst) flags[2] = 'R'; if (encap_tcp->urg) flags[3] = 'U'; if (encap_tcp->ack) flags[4] = 'A'; if (encap_tcp->psh) flags[5] = 'P'; return snprintf(buf, buffleft, "TCP %s[%u] -> %s[%u] %s SEQ:%lu ACK:%lu WIN:%u U:%u", ip_source, ntohs(encap_tcp->source) , ip_dest, ntohs(encap_tcp->dest), &flags[0], encap_tcp->seq, encap_tcp->ack_seq , ntohs(encap_tcp->window), ntohs(encap_tcp->urg_ptr)); break; case IP_UDP: if (pkt->dataleft < sizeof(struct pkt_udp)) return snprintf(buf, buffleft, "UDP %s -> %s Out of data", ip_source, ip_dest); encap_udp = pointer; return snprintf(buf, buffleft, "UDP %s[%u] -> %s[%u] L:%u", ip_source, ntohs(encap_udp->source), ip_dest, ntohs(encap_udp->dest), ntohs(encap_udp->len)); break; default: return snprintf(buf, buffleft, "%s -> %s Protocol %u", ip_source, ip_dest, encap_ip->protocol); break; } log_unreach(); return 0;}int icmp_cmp_type(const struct icmp_type_t *c1, const struct icmp_type_t *c2) { if (c1->type > c2->type) return -1; if (c1->type < c2->type) return 1; return 0;}int icmp_cmp_code(const struct icmp_code_t *c1, const struct icmp_code_t *c2) { if (c1->code > c2->code) return -1; if (c1->code < c2->code) return 1; return 0;}int icmp_init( void ) { int i = 0; icmp_type = list_init(); if (!icmp_type) return ERR_MISC; list_setcmp(icmp_type, (void *) icmp_cmp_type); while(icmp_base_type[i].type != 255) { list_add_sort(icmp_type, &icmp_base_type[i]); i++; } icmp_unreach = icmp_init_codes(ICMP_DESTUNREACH, icmp_base_unreach); icmp_redirect = icmp_init_codes(ICMP_REDIRECT, icmp_base_redirect); icmp_ttl = icmp_init_codes(ICMP_TIMEEXCEEDED, icmp_base_ttl); icmp_param = icmp_init_codes(ICMP_PARMPROBLEM, icmp_base_param); /* open up a file for loggin */#ifdef DEBUG icmp_log = fopen("output/icmp", "w");#else icmp_log = fopen("output/icmp", "w+");#endif if (!icmp_log) log_errno("fopen"); return 0;}struct list_t *icmp_init_codes(int type, struct icmp_code_t codes[]) { int i = 0; struct icmp_type_t search, *data; struct list_t *tmp; tmp = list_init(); if (!tmp) return NULL; list_setcmp(tmp, (void *) icmp_cmp_code); while(codes[i].code != 255) { list_add_sort(tmp, &codes[i]); i++; } search.type = type; i = list_search(icmp_type, &search); if (i > 0) data = list_get(icmp_type, i); if (data) data->code = tmp; return tmp;}void icmp_gui(struct gui_t *p, int y, int x) { WINDOW *draw; char *foot_back, buff[80]; draw = newwin(p->twin->_maxy - 1, p->twin->_maxx - 1, 1, 1); if (!draw) { log_s("newwin failed"); SUNLOCK(&icmp_gui_mutex); return; } wbkgd(draw, COLOR_PAIR(COL_BACK)); scrollok(draw, TRUE); werase(draw); wrefresh(draw); SLOCK(&icmp_gui_mutex); icmp_gui_window = draw; SUNLOCK(&icmp_gui_mutex); while (1) { if (gui_wait(250, 0) == 1) { switch(getch()) { default: goto get_out; break; } } else { stat_process(&icmp_stat); SLOCK(&icmp_gui_mutex); snprintf(&buff[0], 80, "ICMP Packets: %llu Data: %llu %s Drop: %llu", icmp_stat.packets, icmp_stat.readable, icmp_stat.messure, icmp_stat.dropped); wrefresh(draw); gui_footer(p, &buff[0]); SUNLOCK(&icmp_gui_mutex); } }get_out: SLOCK(&icmp_gui_mutex); icmp_gui_window = NULL; SUNLOCK(&icmp_gui_mutex); gui_footer(p, foot_back); scrollok(draw, FALSE); werase(draw); wrefresh(draw); delwin(draw); return;}int icmp_gui_print(char *fmt, ...) { va_list ap; va_start(ap, fmt); SLOCK(&icmp_gui_mutex); vwprintw(icmp_gui_window, fmt, ap); SUNLOCK(&icmp_gui_mutex); va_end(ap); return 0;}struct icmp_type_t icmp_base_type[] = { /* Func code log extra */ {ICMP_ECHOREPLY, "Ping Reply", icmp_ping_reply, NULL, 1}, {ICMP_DESTUNREACH, "Unreachable", icmp_do, NULL, 0}, {ICMP_SOURCEQUENCH, "Source Quence", icmp_do, NULL, 1}, {ICMP_REDIRECT, "Redirect", icmp_do, NULL, 1}, {ICMP_ALT_HOST, "Alt Host", NULL, NULL, 0}, {ICMP_ECHO, "Ping", icmp_ping, NULL, 1}, {ICMP_ROUTER_ADVERT, "Router Advert", NULL, NULL, 1}, {ICMP_ROUTER_SELECT, "Router Select", NULL, NULL, 1}, {ICMP_TIMEEXCEEDED, "Time Exceeded", icmp_do, NULL, 0}, {ICMP_PARMPROBLEM, "Param Problem", icmp_do, NULL, 1}, {ICMP_TIMESTAMP, "Time Stamp", NULL, NULL, 1}, {ICMP_TIMESTAMP_REPLY, "Time Stamp Reply", NULL, NULL, 1}, {ICMP_INFO_REQUEST, "Info Request", NULL, NULL, 1}, {ICMP_INFO_REPLY, "Info Reply", NULL, NULL, 1}, {ICMP_ADDRMASK_REQUEST, "Addr Mask Request", NULL, NULL, 1}, {ICMP_ADDRMASK_REPLY, "Addr Mask Reply", NULL, NULL, 1}, {ICMP_TRACEROUTE, "Traceroute", NULL, NULL, 1}, {ICMP_DATAGRAM_CONVERROR, "DGRAM Conv Error", NULL, NULL, 1}, {ICMP_MOBILE_HOST_REDIRECT, "Mobile Host Redir", NULL, NULL, 1}, {ICMP_IPV6_WHEREAREYOU, "IPV6 Where are you", NULL, NULL, 1}, {ICMP_IPV6_IAMHERE, "IPV6 I am here", NULL, NULL, 1}, {ICMP_MOBILE_REG_REQUEST, "Mobile Reg REQUEST", NULL, NULL, 1}, {ICMP_MOBILE_REG_REPLY, "Mobile Reg Reply", NULL, NULL, 1}, {ICMP_DOMAIN_NAME_REQUEST, "Domain Name Request", NULL, NULL, 1}, {ICMP_DOMAIN_NAME_REPLY, "Domain Name Reply", NULL, NULL, 1}, {ICMP_SKIP, "Skip", NULL, NULL, 1}, {ICMP_PHOTURIS, "Photuris", NULL, NULL, 1}, {255, NULL, NULL, NULL, 0}};struct icmp_code_t icmp_base_unreach[] = { /* Func Log? */ {ICMP_UNREACH_NET, "Network", icmp_do, 0}, {ICMP_UNREACH_HOST, "Host", icmp_do, 0}, {ICMP_UNREACH_PROTOCOL, "Protocol", icmp_do, 1}, {ICMP_UNREACH_PORT, "Port", icmp_do, 0}, {ICMP_UNREACH_FRAGNEEDED, "Frag Needed", icmp_do, 1}, {ICMP_UNREACH_SOURCEROUTE, "Source Route Failed", icmp_do, 1}, {ICMP_UNREACH_DESTNETWORK, "Dest Network", icmp_do, 0}, {ICMP_UNREACH_DESTHOST, "Dest Host", icmp_do, 0}, {ICMP_UNREACH_SOURCEHOST, "Source Host", icmp_do, 1}, {ICMP_UNREACH_PROHIB_NETWORK, "Prohibited Network", icmp_do, 1}, {ICMP_UNREACH_PROHIB_HOST, "Prohibited Host", icmp_do, 1}, {ICMP_UNREACH_DESTNETWORK_TOS, "Network for TOS", icmp_do, 1}, {ICMP_UNREACH_DESTHOST_TOS, "Host for TOS", icmp_do, 1}, {ICMP_UNREACH_PROHIB_ADMIN, "Prohibited Admin", icmp_do, 1}, {ICMP_UNREACH_PRECEDENCE_HOST, "Precedence Host", icmp_do, 1}, {ICMP_UNREACH_PRECEDENCE_CUTOFF,"Precedence Cutoff", icmp_do, 1}, {255, NULL}};struct icmp_code_t icmp_base_redirect[] = { {ICMP_REDIRECT_NETWORK, "Network", icmp_do, 1}, {ICMP_REDIRECT_HOST, "Host", icmp_do, 1}, {ICMP_REDIRECT_TOS_NETWORK, "TOS Network", icmp_do, 1}, {ICMP_REDIRECT_TOS_HOST, "TOD Host", icmp_do, 1}, {255, NULL}};struct icmp_code_t icmp_base_ttl[] = { {ICMP_TTL_TTL, "TTL", icmp_do, 0}, {ICMP_TTL_FRAG, "Fragment", icmp_do, 1}, {255, NULL}};struct icmp_code_t icmp_base_param[] = { {ICMP_PARAM_POINTER, "Pointer", icmp_do, 1}, {ICMP_PARAM_MISSING, "Missing", icmp_do, 1}, {ICMP_PARAM_BADLEN, "Length", icmp_do, 1}, {255, NULL}};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -