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

📄 filter.c

📁 开源的防火墙代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Copyright (c) 2002-2005 Vladislav Goncharov.
*
* Redistribution and use in source forms, with and without modification,
* are permitted provided that this entire comment appears intact.
*
* Redistribution in binary form may occur without any restrictions.
*
* This software is provided ``AS IS'' without any warranties of any kind.
*/

// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs)
//
// $Id: filter.c,v 1.17 2005/03/14 18:28:26 vlad Exp $

/*
* Filtering related routines
*/

#include <ntddk.h>
#include <tdikrnl.h>
#include "sock.h"

#include "filter.h"
#include "memtrack.h"
#include "packet.h"
#include "pid_pname.h"
#include "sids.h"
#include "tdi_fw.h"

// size of cyclic queue for logging
#define REQUEST_QUEUE_SIZE	1024

/* rules chains (main (first entry) and process-related) */
static struct
{
	struct	{
		struct		flt_rule *head;
		struct		flt_rule *tail;
		char		*pname;				// name of process
		BOOLEAN		active;				// filter chain is active
		} chain[MAX_CHAINS_COUNT];
	KSPIN_LOCK	guard;
} g_rules;

/* "ALLOW * * FROM ANY TO ANY" rule */
static struct flt_rule g_allow_all =
{
	{0},
	FILTER_ALLOW,
	IPPROTO_ANY,
	DIRECTION_ANY,
	0,	// from
	0,
	0,
	0,
	0,	// to
	0,
	0,
	0,
	RULE_LOG_LOG,
	"",	// setup mask before using it!
	"startup"		// rule for startup only
};

/* logging request queue */
static struct
{
	struct		flt_request *data;
	KSPIN_LOCK	guard;
	ULONG		head;	/* write to head */
	ULONG		tail;	/* read from tail */
	HANDLE		event_handle;
	PKEVENT		event;
} g_queue;

// init
NTSTATUS	filter_init(void)
{
	NTSTATUS status;
	int i;
	
	pid_pname_init();
	sids_init();
	
	/* rules chain */
	
	KeInitializeSpinLock(&g_rules.guard);
	for (i = 0; i < MAX_CHAINS_COUNT; i++)
		{
		g_rules.chain[i].head = g_rules.chain[i].tail = NULL;
		g_rules.chain[i].pname = NULL;
		g_rules.chain[i].active = FALSE;
		}
	
	// setup the first rule "ALLOW * * FROM ANY TO ANY"
	
	for (i = 0; i < sizeof(g_allow_all.sid_mask); i++)
		g_allow_all.sid_mask[i] = (UCHAR)-1;
	
	g_rules.chain[0].head = malloc_np(sizeof(g_allow_all));
	if (g_rules.chain[0].head == NULL)
		{
		KdPrint(("[tdi_fw] filter_init: malloc_np!\n"));
		return STATUS_INSUFFICIENT_RESOURCES;
		}
	
	memcpy(g_rules.chain[0].head, &g_allow_all, sizeof(g_allow_all));
	
	g_rules.chain[0].tail = g_rules.chain[0].head;
	g_rules.chain[0].active = TRUE;
	
	/* request queue */
	
	KeInitializeSpinLock(&g_queue.guard);
	
	g_queue.data = (struct flt_request *)malloc_np(sizeof(struct flt_request) * REQUEST_QUEUE_SIZE);
	if (g_queue.data == NULL)
		{
		KdPrint(("[tdi_fw] filter_init: malloc_np!\n"));
		return STATUS_INSUFFICIENT_RESOURCES;
		}
	
	memset(g_queue.data, 0, sizeof(struct flt_request) * REQUEST_QUEUE_SIZE);
	
	g_queue.head = g_queue.tail = 0;
	
	return STATUS_SUCCESS;
}

// init for user part starting
NTSTATUS	filter_init_2(void)
{
	NTSTATUS status;
	
	if (g_queue.event_handle == NULL)
		{
		UNICODE_STRING str;
		OBJECT_ATTRIBUTES oa;
		
		RtlInitUnicodeString(&str, L"\\BaseNamedObjects\\tdifw_request");
		InitializeObjectAttributes(&oa, &str, 0, NULL, NULL);
		
		status = ZwCreateEvent(&g_queue.event_handle, EVENT_ALL_ACCESS, &oa, SynchronizationEvent, FALSE);
		if (status != STATUS_SUCCESS)
			{
			KdPrint(("[tdi_fw] filter_init_2: ZwCreateEvent: 0x%x\n", status));
			return status;
			}
		
		}
	
	if (g_queue.event == NULL)
		{
		status = ObReferenceObjectByHandle(g_queue.event_handle, EVENT_ALL_ACCESS, NULL, KernelMode,
						   &g_queue.event, NULL);
		if (status != STATUS_SUCCESS)
			{
			KdPrint(("[tdi_fw] filter_init_2: ObReferenceObjectByHandle: 0x%x\n", status));
			return status;
			}
		
		}
	
	// try to communicate with packet driver
	init_packet();
	
	return STATUS_SUCCESS;
}

// cleanup for user part
void	filter_free_2(void)
{
	free_packet();
	
	if (g_queue.event != NULL)
		{
		ObDereferenceObject(g_queue.event);
		g_queue.event = NULL;
		}
	if (g_queue.event_handle != NULL)
		{
		ZwClose(g_queue.event_handle);
		g_queue.event_handle = NULL;
		}
}

// free
void	filter_free(void)
{
	KIRQL irql;
	struct plist_entry *ple;
	int i;
	
	// clear all chains
	for (i = 0; i < MAX_CHAINS_COUNT; i++)
		clear_flt_chain(i);
	
	/* clear request queue */
	KeAcquireSpinLock(&g_queue.guard, &irql);
	for (i = 0; i < REQUEST_QUEUE_SIZE; i++)
		{
		if (g_queue.data[i].pname != NULL)
			free(g_queue.data[i].pname);
		if (g_queue.data[i].sid_a != NULL)
			free(g_queue.data[i].sid_a);
		}
	free(g_queue.data);
	KeReleaseSpinLock(&g_queue.guard, irql);
	
	set_sid_list(NULL, 0);
	pid_pname_free();
}

#define CHECK_BIT(char_mask, num)	\
		((char_mask)[(num) / 8] & (1 << ((num) % 8)))

// quick filter (I mean "synchronous" (can work at DISPATCH_LEVEL))
int	quick_filter(struct flt_request *request, struct flt_rule *rule)
{
	const struct sockaddr_in *from, *to;
	struct flt_rule *r;
	struct plist_entry *ple;
	KIRQL irql;
	int chain, result, sid_id;
	
	//return FILTER_ALLOW;
	
	// not IP
	if (request->addr.len != sizeof(struct sockaddr_in) ||
		request->addr.from.sa_family != AF_INET ||
		request->addr.to.sa_family != AF_INET)
		{
		KdPrint(("[tdi_fw] quick_filter: not ip addr!\n"));
		return FILTER_DENY;
		}
	
	from = (const struct sockaddr_in *)&request->addr.from;
	to = (const struct sockaddr_in *)&request->addr.to;
	
	// default behavior: DENY and LOG
	result = FILTER_DENY;
	if (rule != NULL)
		{
		memset(rule, 0, sizeof(*rule));
		rule->result = result;
		rule->log = TRUE;
		strcpy(rule->rule_id, "default");
		}
	
	chain = pid_pname_get_context(request->pid);
	if (!g_rules.chain[chain].active)
		{
		// chain is not active; don't check request
		return result;
		}
	
	if (request->sid_a != NULL)
		sid_id = get_sid_id(request->sid_a, request->sid_a_size);
	else
		sid_id = 0;		// default sid_id
	
	// quick filter
	KeAcquireSpinLock(&g_rules.guard, &irql);
	
#define CHECK_ADDR_PORT(r_addr_from, r_mask_from, r_port_from, r_port2_from,										\
						r_addr_to, r_mask_to, r_port_to, r_port2_to)												\
		((r_addr_from & r_mask_from) == (from->sin_addr.s_addr & r_mask_from) &&								\
		 (r_addr_to   & r_mask_to) 	 == (to->sin_addr.s_addr   & r_mask_to)   &&											\
		 (r_port_from == 0 || 																					\
			((r_port2_from == 0) ? (r_port_from == from->sin_port) :							\
				(ntohs(from->sin_port) >= ntohs(r_port_from) && ntohs(from->sin_port) <= ntohs(r_port2_from)))) &&	\
		 (r_port_to == 0 ||																			\
			((r_port2_to == 0) ? (r_port_to == to->sin_port) :									\
				(ntohs(to->sin_port) >= ntohs(r_port_to) && ntohs(to->sin_port) <= ntohs(r_port2_to)))))			\
		
	// go through rules
	for (r = g_rules.chain[chain].head; r != NULL; r = r->next)
	// Can anybody understand it?
		if ((r->proto == IPPROTO_ANY || r->proto == request->proto) 							
		&&  ((r->direction != DIRECTION_ANY && r->direction == request->direction 			
				&& CHECK_ADDR_PORT(r->addr_from, r->mask_from, r->port_from, r->port2_from,	
							r->addr_to, r->mask_to, r->port_to, r->port2_to)) 					
			|| (r->direction == DIRECTION_ANY													 
				&& ((request->direction == DIRECTION_OUT 										
					&& CHECK_ADDR_PORT(r->addr_from, r->mask_from, r->port_from, r->port2_from,		
							r->addr_to, r->mask_to, r->port_to, r->port2_to)) 					
				|| (request->direction == DIRECTION_IN 										
					&& CHECK_ADDR_PORT(r->addr_to, r->mask_to, r->port_to,						
							r->port2_to, r->addr_from, r->mask_from, r->port_from, r->port2_from))))) 
		&& CHECK_BIT(r->sid_mask, sid_id))
		{
		result = r->result;
		KdPrint(("[tdi_fw] quick_filter: found rule with result: %d\n", result));
		
		if (rule != NULL)
			{
			memcpy(rule, r, sizeof(*rule));
			
			rule->next = NULL;	// useless field
			}
		
		break;
		}
	
	
	KeReleaseSpinLock(&g_rules.guard, irql);
	

⌨️ 快捷键说明

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