NIDS-端口扫描检测初步(抓包部分)

原来的代码耦合性太高了,我重构了一下,模块化了。

扫描部分还待扩充


头文件:

config.h

#ifndef lib_pcap_pcap_h
#include "pcap.h"
#endif

#ifndef HAVE_PARAM_H
#include "param.h"
#endif

#ifndef HAVE_CONFIG_H
#define HAVE_CONFIG_H

/*
	IPSIZE			IP地址的长度
	MACSIZE			MAC地址的长度
	PORTNUM			PORT的个数
*/
#define IPSIZE 16					
#define MACSIZE 14
#define PORTNUM 65536

const int judge_ip_times = 4;		// 设置判为可疑的次数
const int judge_port_times = 100;
const char port_scan_log[] = "port_scan_log.txt";

#endif		// CONFIG_H


dnmc_packet_data.h

#ifndef HAVE_CONFIG_H
#include "config.h"
#endif

#ifndef HAVE_DNMC_PACKET_DATA_H
#define HAVE_DNMC_PACKET_DATA_H

typedef struct protocol_type {
	int dport_hash[PORTNUM];
	int dport_last_time[PORTNUM];		// ??预想画出特征曲线
}protocol_type;

typedef struct smac_info {
	char *dmac;
	struct protocol_type *pprot_type;

	struct smac_info* next;
}smac_info;

typedef struct list_head {
	char *smac;
	struct smac_info *psmac_info;

	struct list_head *next;
}list_head;

typedef struct rule_list_node {
	char *name;
	int mode;
	int rval;							// 0表示不检测,1表示检测
	struct rule_list_node* next;
	struct list_head* rule_list;
}rule_list_node;

#endif		// DNMC_PACKET_DATA_H

main.h

#ifndef lib_pcap_pcap_h
#include "pcap.h"
#endif

#ifdef WINDOWS
#define unsigned (unsigned int)
#endif

#ifdef LINUX
#define unsigned (unsigned long)
#endif

char *packet_filter;				// 需要从文件中读取过滤数据参数

struct pcap_pkthdr **pool_header;	// 数据包池
u_char **pool_pkt_data;
u_int pool_in_index;
u_int pool_out_index;

packet.h

#ifndef HAVE_CONFIG_H
#include "config.h"
#define HAVE_CONFIG_H
#endif


#ifndef HAVE_PACKET_H
#define HAVE_PACKET_H

// 以太网协议格式的定义
typedef struct ether_header {
	u_char dhost[6];		// 目标地址
	u_char shost[6];		// 源地址
	u_short type;			// 以太网类型
}ether_header;

// 用户保存4字节的IP地址
typedef struct ip_address {
	u_char byte1;
	u_char byte2;
	u_char byte3;
	u_char byte4;
}ip_address;

// 用于保存IPV4的首部
typedef struct ip_header {
#ifdef WORDS_BIGENDIAN
	u_char ip_version : 4, header_length : 4;
#else
	u_char header_length : 4, ip_version : 4;
#endif

	u_char ver_ihl;		// 版本以及首部长度,各4位
	u_char tos;			// 服务质量
	u_short tlen;		// 总长度
	u_short identification;		// 身份识别
	u_short offset;			// 分组偏移
	u_char ttl;			// 生命周期
	u_char protocol;		// 协议类型
	u_short checksum;		// 包头测验码
	ip_address saddr;	// 源IP地址
	ip_address daddr;	// 目的IP地址
	u_int op_pad;		//可选 填充字段
}ip_header;

// 保存TCP首部
typedef struct tcp_header {
	u_short sport;
	u_short dport;
	u_int sequence;		// 序列码
	u_int ack;					// 回复码

#ifdef WORDS_BIGENDIAN
	u_char offset : 4, reserved : 4;		// 偏移 预留
#else
	u_char reserved : 4, offset : 4;		// 预留 偏移
#endif
	
	u_char flags;				// 标志
	u_short windows;			// 窗口大小
	u_short checksum;			// 校验和
	u_short urgent_pointer;		// 紧急指针
}tcp_header;

// 保存ICMP数据包
typedef struct icmp_header {
	u_char type;
	u_char code;
	u_short checksum;
	u_short id;
	u_short sequence;
}icmp_header;

#endif		// PACKET_H

param.h

#ifndef lib_pcap_pcap_h
#include "pcap.h"
#endif

#ifndef HAVE_PARAM_H
#define HAVE_PARAM_H

extern char *packet_filter;				// 需要从文件中读取过滤数据参数

extern struct pcap_pkthdr **pool_header;	// 数据包池
extern u_char **pool_pkt_data;
extern u_int pool_in_index;
extern u_int pool_out_index;

#endif	// PARAM_H

protocol_packet_handle.h

#ifndef HAVE_CONFIG_H
#include "config.h"
#endif

extern void tcp_protocol_packet_handle(
	u_char *argument, 
	const struct pcap_pkthdr *packet_header, 
	const u_char *packet_content 
);

extern void udp_protocol_packet_handle(
	u_char *argument,
	const struct pcap_pkthdr *packet_header,
	const u_char *packet_content
);

extern void icmp_protocol_packet_handle(
	u_char *argument,
	const struct pcap_pkthdr *packet_header,
	const u_char *packet_content
);

extern void ip_protocol_packet_handle(
	u_char *argument, 
	const struct pcap_pkthdr *packet_header, 
	const u_char *packet_content 
);

extern void ethernet_protocol_packet_handle (
	u_char *argument,
	const struct pcap_pkthdr *packet_header, 
	const u_char *packet_content
);

port_scan.h

#ifndef HAVE_CONFIG_H
#include "config.h"
#endif

#ifndef HAVE_PARAM_H
#include "param.h"
#endif

unsigned _stdcall port_scanThreadFunc(void* pArguments);



源文件:

main.cpp

#include <iostream>
#include <process.h>

#include "main.h"
#include "port_scan.h"
#include "protocol_packet_handle.h"
#include "dnmc_packet_data.h"
#include "packet.h"
#include "config.h"


#define HAVE_REMOTE
#include "remote-ext.h"

using namespace std;

#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "wpcap.lib")

int sys_init(pcap_t **adhandle) {
	pcap_if_t *alldevs;
	pcap_if_t *d;
	
	char errbuf[PCAP_ERRBUF_SIZE];
	int inum;
	int i = 0;
	u_int netmask;
	char packet_filter[] = "ip and tcp";
	struct bpf_program fcode;

	pool_in_index = 0;
	pool_out_index = 0;

	// 获得设备列表 pcap_findalldevs_ex()

	if(pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1) {
		fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);
		exit(1);
	}

	for(d = alldevs; d; d = d->next) {
		printf("%d. %s", ++i, d->name);
		if(d->description) {
			printf("(%s)\n", d->description);
		}
		else {
			printf("No description available\n");
		}
	}
	
	if(0 == i) {
		printf("\nNo interface found!Make sure WinPcap is installed\n");
		return -1;
	}

	printf("Enter the interface number(1-%d):", i);
	scanf_s("%d", &inum);
	if(inum < 1 || inum > i) {
		printf("\nInterface number out of range.\n");
		pcap_freealldevs(alldevs);
		return -1;
	}

	for(d = alldevs, i = 0; i < inum-1; d=d->next, i++);
	// 跳转到该设备,打开适配器

	// 设备名,要捕捉的数据包的部分(65536保证能捕获到不同数据链路层上的每个数据包的全部内容),混杂模式,读取超时时间,错误缓冲池
	if((*adhandle = pcap_open_live(d->name, 65536, 1, 1000, errbuf)) == NULL) {
		fprintf(stderr, "\nUnable to open the adapter.%s is not supported by WinPcap\n", errbuf);
		pcap_freealldevs(alldevs);
		return -1;
	}
	// 检查数据链路层(只考虑了以太网)
	if(pcap_datalink(*adhandle) != DLT_EN10MB) {
		fprintf(stderr, "\nThis program works only on Ethernet networks.\n");
		pcap_freealldevs(alldevs);
		return -1;
	}

	if(d->addresses != NULL) {
		// 获得接口的第一个地址的掩码
		netmask = ((struct sockaddr_in*)(d->addresses->netmask))->sin_addr.S_un.S_addr;
	}
	else {
		netmask = 0xffffff;
	}

	// 编译过滤器
	if(pcap_compile(*adhandle, &fcode, packet_filter, 1, netmask) < 0) {
		fprintf(stderr, "\nUnable to compile the packet filter.Check the syntax\n");
		pcap_freealldevs(alldevs);
		return -1;
	}
	
	// 设置过滤器
	
	if(pcap_setfilter(*adhandle, &fcode) < 0) {
		fprintf(stderr, "\nError setting the filter.\n");
		pcap_freealldevs(alldevs);
		return -1;
	}
	printf("\nlistenting on %s...\n", d->description);

	pcap_freealldevs(alldevs);

	return 0;
}

int sys_start(pcap_t *adhandle) {
	struct pcap_pkthdr *header;
	const u_char *pkt_data;
	int res;

	struct tm *ltime;
	time_t local_tv_sec;
	char timestr[16];
	ip_header *ih;
	
	while((res = pcap_next_ex(adhandle, &header, &pkt_data)) >= 0) {	

		// 请求超时
		if(0 == res) {
			continue;
		}

		pool_header[pool_in_index] = header;
		pool_pkt_data[pool_in_index] = const_cast<u_char*>(pkt_data);
		pool_in_index++;

		// 分析数据包
		ethernet_protocol_packet_handle(NULL, header, pkt_data);		改为Thread

/*
		// 将时间戳转换成可识别的格式
		local_tv_sec = header->ts.tv_sec;
		ltime = localtime(&local_tv_sec);
		strftime(timestr, sizeof(timestr), "%H:%M:%S", ltime);
		ih = (ip_header *)(pkt_data + 14); //以太网头部长度

		// 输出时间和IP信息
		printf("%s.%.6d len:%d ", timestr, header->ts.tv_usec, header->len);

		printf("%d.%d.%d.%d -> %d.%d.%d.%d\n",
	        ih->saddr.byte1,
	        ih->saddr.byte2,
	        ih->saddr.byte3,
	        ih->saddr.byte4,
	        ih->daddr.byte1,
	        ih->daddr.byte2,
	        ih->daddr.byte3,
			ih->daddr.byte4);
*/

	}

	
	if(-1 == res) {
		printf("Error reading the packet:%s\n", pcap_geterr(adhandle));
		return -1;
	}

	return 0;
}

int main(int argc, char *argv[]) {
	pcap_t *adhandle;

	HANDLE hThread_portscan;
	unsigned ps_threadID;

	sys_init(&adhandle);		// 系统初始化
	sys_start(adhandle);		// 启动抓包

	hThread_portscan = (HANDLE)_beginthreadex(NULL, 0, &port_scanThreadFunc, NULL, 0, &ps_threadID);		//端口扫描线程

	return 0;
}

protocol_packet_handle.cpp

#ifndef HAVE_CONFIG_H
#include "config.h"
#endif

#ifndef HAVE_PACKET_H
#include "packet.h"
#endif

void tcp_protocol_packet_handle(
	u_char *argument, 
	const struct pcap_pkthdr *packet_header, 
	const u_char *packet_content 
) {
	struct tcp_header *tcp_protocol;
	u_short sport;
	u_short dport;
	int header_length;
	u_short windows;
	u_short urgent_pointer;
	u_int sequence;
	u_int acknowledgement;
	u_short checksum;
	u_char flags;

	printf("===========TCP Protocol===========\n");

	tcp_protocol = (struct tcp_header*)(packet_content + 14 + 20);
	sport = ntohs(tcp_protocol->sport);
	dport = ntohs(tcp_protocol->dport);
	header_length = tcp_protocol->offset * 4;
	sequence = ntohl(tcp_protocol->sequence);
	acknowledgement = ntohl(tcp_protocol->ack);
	windows = ntohs(tcp_protocol->windows);
	urgent_pointer = ntohs(tcp_protocol->urgent_pointer);
	flags = tcp_protocol->flags;
	checksum = ntohs(tcp_protocol->checksum);


	if(flags & 0x08) printf("PSH");
	if(flags & 0x10) printf("ACK");
	if(flags & 0x02) printf("SYN");
	if(flags & 0x20) printf("URG");
	if(flags & 0x01) printf("FIN");
	if(flags & 0x04) printf("RST");
	printf("\n");
}

void udp_protocol_packet_handle(
	u_char *argument,
	const struct pcap_pkthdr *packet_header,
	const u_char *packet_content
) {

}

void icmp_protocol_packet_handle(
	u_char *argument,
	const struct pcap_pkthdr *packet_header,
	const u_char *packet_content
) {
	struct icmp_header *icmp_protocol;
	icmp_protocol = (struct icmp_header*)(packet_content + 14 + 20);
	printf("===========ICMP Protocol==========\n");
	printf("ICMP Type: %d\n", icmp_protocol->type);

	switch(icmp_protocol->type) {
	case 8:
		// 回显请求报文
		break;
	case 0:
		// 回显应答报文
		break;
	default:
		break;
	}
}

void ip_protocol_packet_handle(
	u_char *argument, 
	const struct pcap_pkthdr *packet_header, 
	const u_char *packet_content 
) {
	struct ip_header *ip_protocol;
	u_int header_length;
	u_int offset;
	u_char tos;
	u_short checksum;

	printf("===========IP Protocol===========\n");

	ip_protocol = (struct ip_header*)(packet_content + 14);
	header_length = ip_protocol->header_length * 4;
	checksum = ntohs(ip_protocol->checksum);
	tos = ip_protocol->tos;
	offset = ntohs(ip_protocol->offset);

	switch(ip_protocol->protocol) {
	case 6:
		tcp_protocol_packet_handle(argument, packet_header, packet_content);
		break;
	case 17:
		udp_protocol_packet_handle(argument, packet_header, packet_content);
		break;
	case 1:
		icmp_protocol_packet_handle(argument, packet_header, packet_content);
		break;
	default:
		break;
	}
}


void ethernet_protocol_packet_handle (
	u_char *argument, 
	const struct pcap_pkthdr *packet_header, 
	const u_char *packet_content
) {
	u_short ethernet_type;		// 以太网类型
	struct ether_header *ethernet_protocol;		// 以太网协议变量
	u_char *mac_string;			// 以太网地址
	
	ethernet_protocol = (struct ether_header*)packet_content;		// 获取以太网数据内容
	printf("Ethernet type is : \n");
	ethernet_type = ntohs(ethernet_protocol->type);	// 获取以太网类型
	printf("	%04x\n", ethernet_type);
		
	switch(ethernet_type) {
	case 0x0800:
		printf("The network layer is IP protocol\n");
		break;
	case 0x0806:
		printf("The network layer is ARP protocol\n");
		break;
	default:
		break;
	}

	// 获取以太网源地址
	printf("MAC Source Address is : \n");
	mac_string = ethernet_protocol->shost;
	printf
		("	%02x:%02x:%02x:%02x:%02x:%02x\n", 
		*mac_string,
		*(mac_string + 1),
		*(mac_string + 2),
		*(mac_string + 3),
		*(mac_string + 4),
		*(mac_string + 5)
		);

	// 获取以太网目的地址
	printf("MAC Target Address is : \n");
	mac_string = ethernet_protocol->dhost;
	printf
		("	%02x:%02x:%02x:%02x:%02x:%02x\n", 
		*mac_string,
		*(mac_string + 1),
		*(mac_string + 2),
		*(mac_string + 3),
		*(mac_string + 4),
		*(mac_string + 5)
		);

	switch(ethernet_type) {
	case 0x0800:
		ip_protocol_packet_handle(argument, packet_header, packet_content);
		break;
	default:
		break;
	}
}


port_scan.cpp


#ifndef HAVE_CONFIG_H
#include "config.h"
#endif

#ifndef HAVE_PACKET_H
#include "packet.h"
#endif

unsigned _stdcall port_scanThreadFunc(void* pArguments) {
	
	return 0;
}




你可能感兴趣的:(NIDS-端口扫描检测初步(抓包部分))