⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 packet.c

📁 开源的防火墙代码
💻 C
📖 第 1 页 / 共 2 页
字号:
			
			if (buffer_len < sizeof(struct tcp_hdr))
				{
				KdPrint(("[tdi_fw] process_transp: too small buffer for tcp_hdr! (%u)\n",
					buffer_len));
				return FALSE;
				}
			
			tcp_hdr = (struct tcp_hdr *)pointer;
			
			process_tcp(direction, tcp_hdr, log_nfo);
			
			break;
			
		case IPPROTO_UDP:
			
			/* process udp_hdr */
			
			if (buffer_len < sizeof(struct udp_hdr))
				{
				KdPrint(("[tdi_fw] process_transp: too small buffer for udp_hdr! (%u)\n",
					buffer_len));
				return FALSE;
				}
			
			udp_hdr = (struct udp_hdr *)pointer;
			
			process_udp(direction, udp_hdr, log_nfo);
			
			break;
			
		case IPPROTO_ICMP:
			
			/* process icmp_hdr */
			
			if (buffer_len < sizeof(struct icmp_hdr))
				{
				KdPrint(("[tdi_fw] process_transp: too small buffer for icmp_hdr! (%u)\n",
					buffer_len));
				return FALSE;
				}
			
			icmp_hdr = (struct icmp_hdr *)pointer;
			
			process_icmp(direction, icmp_hdr, log_nfo);
			
			break;
			
		default:
			KdPrint(("[tdi_fw] process_transp: ipproto = %d\n", proto));
		}
	
	return TRUE;
}

/* process TCP header and check it against our information about connection objects */
void	process_tcp(int direction, struct tcp_hdr *tcp_hdr, struct flt_request *log_nfo)
{
#if DBG
	char flags[7];
	
	flags[0] = (tcp_hdr->th_flags & TH_FIN) ? 'F' : ' ';
	flags[1] = (tcp_hdr->th_flags & TH_SYN) ? 'S' : ' ';
	flags[2] = (tcp_hdr->th_flags & TH_RST) ? 'R' : ' ';
	flags[3] = (tcp_hdr->th_flags & TH_PUSH) ? 'P' : ' ';
	flags[4] = (tcp_hdr->th_flags & TH_ACK) ? 'A' : ' ';
	flags[5] = (tcp_hdr->th_flags & TH_URG) ? 'U' : ' ';
	flags[6] = '\0';
	
	KdPrint(("[tdi_fw] tcp %d -> %d (%s)\n",
		ntohs(tcp_hdr->th_sport),
		ntohs(tcp_hdr->th_dport),
		flags));
#endif
	
	log_nfo->packet.tcp_flags = tcp_hdr->th_flags;
	((struct sockaddr_in *)(&log_nfo->addr.from))->sin_port = tcp_hdr->th_sport;
	((struct sockaddr_in *)(&log_nfo->addr.to))->sin_port = tcp_hdr->th_dport;
	
	check_packet(log_nfo);
}

/* process UDP header and check it against our informatation about address objects */
void	process_udp(int direction, struct udp_hdr *udp_hdr, struct flt_request *log_nfo)
{
	KdPrint(("[tdi_fw] udp %d -> %d\n", ntohs(udp_hdr->uh_sport), ntohs(udp_hdr->uh_dport)));
	
	((struct sockaddr_in *)(&log_nfo->addr.from))->sin_port = udp_hdr->uh_sport;
	((struct sockaddr_in *)(&log_nfo->addr.to))->sin_port = udp_hdr->uh_dport;
	
	check_packet(log_nfo);
}

/* process ICMP header */
void	process_icmp(int direction, struct icmp_hdr *icmp_hdr, struct flt_request *log_nfo)
{
	KdPrint(("[tdi_fw] icmp (%d.%d)\n", icmp_hdr->icmp_type, icmp_hdr->icmp_code));
	
	log_nfo->packet.icmp_type = icmp_hdr->icmp_type;
	log_nfo->packet.icmp_code = icmp_hdr->icmp_code;
	
	check_packet(log_nfo);
}

void	init_tcp_states(void)
{
	// init g_tcp_states sparse array (don't define RST flags)
	
#define DEFINE_STATE_IN(state, index, flags_set, flags_not_set)  \
		g_tcp_states[(state)][DIRECTION_IN][(index)].tcp_flags_set = (flags_set);  \
		g_tcp_states[(state)][DIRECTION_IN][(index)].tcp_flags_not_set = (flags_not_set)
	
#define DEFINE_STATE_OUT(state, index, flags_set, flags_not_set)  \
		g_tcp_states[(state)][DIRECTION_OUT][(index)].tcp_flags_set = (flags_set);  \
		g_tcp_states[(state)][DIRECTION_OUT][(index)].tcp_flags_not_set = (flags_not_set)
	
	// -connection establishment
	
	// --active (outgoing) connection
	
	// ---SYN retransmitting + 3rd positive answer
	DEFINE_STATE_OUT(TCP_STATE_SYN_SENT, 0, TH_SYN, TH_ACK);
	DEFINE_STATE_OUT(TCP_STATE_SYN_SENT, 1, TH_ACK, TH_SYN | TH_FIN);
	
	// ---positive answer
	DEFINE_STATE_IN(TCP_STATE_SYN_SENT, 0, TH_SYN | TH_ACK, 0);
	
	// --passive (incoming) connection
	
	// ---positive answer
	DEFINE_STATE_OUT(TCP_STATE_SYN_RCVD, 0, TH_SYN | TH_ACK, 0);
	
	// ---last connect step: ACK or FIN(ACK)
	DEFINE_STATE_IN(TCP_STATE_SYN_RCVD, 0, TH_ACK, TH_FIN | TH_SYN);
	DEFINE_STATE_IN(TCP_STATE_SYN_RCVD, 1, TH_FIN, TH_SYN);
	
	// -established in/out: ACK, FIN
	DEFINE_STATE_IN(TCP_STATE_ESTABLISHED_IN, 0, TH_ACK, TH_FIN | TH_SYN);
	DEFINE_STATE_IN(TCP_STATE_ESTABLISHED_IN, 1, TH_FIN, TH_SYN);
	DEFINE_STATE_OUT(TCP_STATE_ESTABLISHED_IN, 0, TH_ACK, TH_FIN | TH_SYN);
	DEFINE_STATE_OUT(TCP_STATE_ESTABLISHED_IN, 1, TH_FIN, TH_SYN);
	
	DEFINE_STATE_IN(TCP_STATE_ESTABLISHED_OUT, 0, TH_ACK, TH_FIN | TH_SYN);
	DEFINE_STATE_IN(TCP_STATE_ESTABLISHED_OUT, 1, TH_FIN, TH_SYN);
	
	// --peer didn't receive 3rd ACK packet
	DEFINE_STATE_IN(TCP_STATE_ESTABLISHED_OUT, 2, TH_ACK | TH_SYN, TH_FIN);
	
	DEFINE_STATE_OUT(TCP_STATE_ESTABLISHED_OUT, 0, TH_ACK, TH_FIN | TH_SYN);
	DEFINE_STATE_OUT(TCP_STATE_ESTABLISHED_OUT, 1, TH_FIN, TH_SYN);
	
	// -connection closing
	DEFINE_STATE_IN(TCP_STATE_FIN_WAIT1, 0, TH_FIN, TH_SYN);
	DEFINE_STATE_IN(TCP_STATE_FIN_WAIT1, 1, TH_ACK, TH_FIN | TH_SYN);
	DEFINE_STATE_OUT(TCP_STATE_FIN_WAIT1, 0, TH_FIN, TH_SYN);
	DEFINE_STATE_OUT(TCP_STATE_FIN_WAIT1, 1, TH_ACK, TH_FIN | TH_SYN);
	
	DEFINE_STATE_IN(TCP_STATE_FIN_WAIT2, 0, TH_FIN, TH_SYN);
	DEFINE_STATE_IN(TCP_STATE_FIN_WAIT2, 1, TH_ACK, TH_FIN | TH_SYN);
	DEFINE_STATE_OUT(TCP_STATE_FIN_WAIT2, 0, TH_ACK, TH_FIN | TH_SYN);
	
	DEFINE_STATE_OUT(TCP_STATE_CLOSE_WAIT, 0, TH_ACK, TH_FIN | TH_SYN);
	DEFINE_STATE_OUT(TCP_STATE_LAST_ACK, 0, TH_FIN, TH_SYN);
	DEFINE_STATE_OUT(TCP_STATE_LAST_ACK, 1, TH_ACK, TH_FIN | TH_SYN); // answer on FIN retransmitting
	DEFINE_STATE_IN(TCP_STATE_LAST_ACK, 0, TH_ACK, TH_FIN | TH_SYN);
	DEFINE_STATE_IN(TCP_STATE_LAST_ACK, 1, TH_FIN, TH_SYN);		// FIN retransmitting
	
	// -in "closed" state all incoming packets are allowed (except single SYN)
	DEFINE_STATE_IN(TCP_STATE_CLOSED, 0, TH_ACK, 0);
	DEFINE_STATE_IN(TCP_STATE_CLOSED, 1, TH_FIN, 0);
	
	// -and RST out too
	DEFINE_STATE_OUT(TCP_STATE_CLOSED, 0, TH_RST, 0);
	
	// ??? I saw this packet sometimes (maybe there's a bug in my code?)
	DEFINE_STATE_OUT(TCP_STATE_CLOSED, 1, TH_ACK, TH_FIN | TH_SYN);
}

/*
* check packet against state in obj_tbl
*
* NOTE: this function is experimental ONLY!!!
* To make work it better I should specify interface information: IP address and network mask
*/
void	check_packet(struct flt_request *log_nfo)
{
	BOOLEAN correct = FALSE;
	struct sockaddr_in *addr_from = (struct sockaddr_in *)&log_nfo->addr.from,
					*addr_to = (struct sockaddr_in *)&log_nfo->addr.to;
	
	// check it
	
	if (log_nfo->proto == IPPROTO_TCP)
		{
		
		/* TCP protocol */
		
		if ((log_nfo->packet.tcp_flags & TH_SYN) &&
			!(log_nfo->packet.tcp_flags & TH_ACK) &&
			log_nfo->direction == DIRECTION_IN)
			{
			
			// active incoming connection (SYN+ ACK-): check against listening address objects
			correct = is_listen(addr_to->sin_addr.s_addr, addr_to->sin_port, IPPROTO_TCP) ||
				  is_listen(0, addr_to->sin_port, IPPROTO_TCP);
			
			}
		else	{
			int state;
			
			// just check address & port against connection table
			if (log_nfo->direction == DIRECTION_OUT)
				{
				state = get_tcp_conn_state(addr_from->sin_addr.s_addr, addr_from->sin_port,
							   addr_to->sin_addr.s_addr, addr_to->sin_port);
				if (state == TCP_STATE_NONE)	// source addr can be 0
					state = get_tcp_conn_state(0, addr_from->sin_port, addr_to->sin_addr.s_addr, addr_to->sin_port);
				}
			else	{				// DIRECTION_IN
				state = get_tcp_conn_state(addr_to->sin_addr.s_addr, addr_to->sin_port,
							   addr_from->sin_addr.s_addr, addr_from->sin_port);
				if (state == TCP_STATE_NONE)	// dest addr can be 0
					state = get_tcp_conn_state(0, addr_to->sin_port, addr_from->sin_addr.s_addr, addr_from->sin_port);
				}
			
			if (log_nfo->packet.tcp_flags & TH_RST)
				correct = (state != TCP_STATE_NONE);
			else	{
				
				// check connection state & header flags against g_tcp_states
				int i;
				
				for (i = 0; i < MAX_FLAGS; i++)
					{
					UCHAR tcp_flags_set = g_tcp_states[state][log_nfo->direction][i].tcp_flags_set;
					if (tcp_flags_set == 0)
						break;
					
					if ((tcp_flags_set & log_nfo->packet.tcp_flags) == tcp_flags_set &&
						!(g_tcp_states[state][log_nfo->direction][i].tcp_flags_not_set & log_nfo->packet.tcp_flags))
						{
						correct = TRUE;
						break;
						}
					}
				}
			
			if (!correct && (log_nfo->packet.tcp_flags & TH_RST) && log_nfo->direction == DIRECTION_OUT)
				{
				// don't log RSTs on opened ports
				correct = is_listen(addr_from->sin_addr.s_addr, addr_from->sin_port, IPPROTO_TCP) ||
					  is_listen(0, addr_from->sin_port, IPPROTO_TCP);
				}
			
			if (!correct)
				log_nfo->packet.tcp_state = state;
			}
		
		}
	else if (log_nfo->proto == IPPROTO_UDP)
		{
		
		// UDP: check it against listening address objects
		if (log_nfo->direction == DIRECTION_IN)
			{
			// incoming datagram: check "to" addr & port
			correct = is_listen(addr_to->sin_addr.s_addr, addr_to->sin_port, log_nfo->proto) ||
				  is_listen(0, addr_to->sin_port, log_nfo->proto) ||
				  (log_nfo->packet.is_broadcast &&
				   (addr_to->sin_addr.s_addr == (ULONG)-1 ||
				   is_bcast_listen(addr_to->sin_addr.s_addr, addr_to->sin_port, log_nfo->proto)));
			
			}
		else	{				// DIRECTION_OUT
			// outgoing datagram: check "from" addr & port
			correct = is_listen(addr_from->sin_addr.s_addr, addr_from->sin_port, log_nfo->proto) ||
				  is_listen(0, addr_from->sin_port, log_nfo->proto) ||
				  (log_nfo->packet.is_broadcast && is_bcast_listen(addr_from->sin_addr.s_addr, addr_from->sin_port, log_nfo->proto));
			}
		}
	
	if (correct)
		log_nfo->pid = (ULONG)-1;	// don't log this packet
}

#if _WIN32_WINNT >= 0x0500
/* set or remove IP firewall hook */
NTSTATUS	set_hook(PacketFilterExtensionPtr hook_fn)
{
	UNICODE_STRING ipfilter_name;
	NTSTATUS status;
	PFILE_OBJECT fileobj = NULL;
	PDEVICE_OBJECT devobj;
	PF_SET_EXTENSION_HOOK_INFO hook_nfo;
	PIRP irp = NULL;
	IO_STATUS_BLOCK isb;
	
	RtlInitUnicodeString(&ipfilter_name, DD_IPFLTRDRVR_DEVICE_NAME);
	
	status = IoGetDeviceObjectPointer(
					    &ipfilter_name,
					    STANDARD_RIGHTS_ALL,
					    &fileobj,
					    &devobj);
	if (status != STATUS_SUCCESS)
		goto done;
	
	hook_nfo.ExtensionPointer = hook_fn;
	
	irp = IoBuildDeviceIoControlRequest(IOCTL_PF_SET_EXTENSION_POINTER,
					    devobj, &hook_nfo, sizeof(hook_nfo),
					    NULL, 0, FALSE, NULL, &isb);
	if (irp == NULL)
		{
		status = STATUS_INSUFFICIENT_RESOURCES;
		goto done;
		}
	
	status = IoCallDriver(devobj, irp);
	irp = NULL;
	
	done:
	/* cleanup */
	if (fileobj != NULL)
		ObDereferenceObject(fileobj);
	if (irp != NULL)
		IoFreeIrp(irp);
	
	return status;
}

/* firewall callback hook proc */
PF_FORWARD_ACTION	hook_proc(
				    unsigned char *PacketHeader,
				    unsigned char *Packet,
				    unsigned int PacketLength,
				    unsigned int RecvInterfaceIndex,
				    unsigned int SendInterfaceIndex,
				    IPAddr RecvLinkNextHop,
				    IPAddr SendLinkNextHop)
{
	BOOLEAN log = FALSE, result = FALSE;
	int direction, iface;
	struct ip_hdr *ip_hdr;
	struct flt_request log_nfo;
	
	direction = (RecvInterfaceIndex != INVALID_PF_IF_INDEX) ? DIRECTION_IN : DIRECTION_OUT;
	iface = (direction == DIRECTION_IN) ? RecvInterfaceIndex : SendInterfaceIndex;
	
	KdPrint(("[tdi_fw] hook_proc: direction = %s; iface = 0x%x; len = %d\n",
		direction == DIRECTION_IN ? "in" : "out", iface, PacketLength));
	
	memset(&log_nfo, 0, sizeof(log_nfo));
	log_nfo.struct_size = sizeof(log_nfo);
	log_nfo.direction = direction;
	
	// ...have not access to ethernet handler
	
	ip_hdr = (struct ip_hdr *)PacketHeader;
	
	if (ip_hdr->ip_dst == 0x0100007f)
		{		// don't work with loopback interface
		result = TRUE;
		goto done;
		}
	
	// check we've got the first fragment (don't work with another!)
	if ((ntohs(ip_hdr->ip_off) & IP_OFFMASK) != 0 && (ip_hdr->ip_off & IP_DF) == 0)
		{
		
		KdPrint(("[tdi_fw] hook_proc: got not first fragment\n"));
		
		result = TRUE;
		log = FALSE;
		goto done;
		}
	
	process_ip(direction, ip_hdr, &log_nfo);
	
	// no way to determine broadcasts without knowing interface IP/mask :-(
	log_nfo.packet.is_broadcast = 1;	// for datagram processing code
	
	result = process_transp(direction, ip_hdr->ip_p, ip_hdr, Packet, PacketLength, &log_nfo);
	if (!result)
		goto done;
	
	// using log_nfo->pid as signal to log it
	log = (log_nfo.pid == 0);
	
	result = TRUE;		// packet headers looks like valid
	
	done:
	if (log){
		log_nfo.result = result ? FILTER_PACKET_LOG : FILTER_PACKET_BAD;
		log_nfo.pid = (ULONG)-1;
		log_request(&log_nfo);
		}
	
	return result ? PF_FORWARD : PF_DROP;
}
#endif /* _WIN32_WINNT >= 0x0500 */

#endif /* USE_PACKET_ENGINE */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -